GCC Code Coverage Report


Directory: ./
File: sql/binlog.cc
Date: 2022-12-13 11:44:05
Exec Total Coverage
Lines: 4228 4700 90.0%
Branches: 5373 10093 53.2%

Line Branch Exec Source
1 /* Copyright (c) 2009, 2022, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "sql/binlog.h"
24
25 #include "my_config.h"
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <time.h>
33
34 #include "lex_string.h"
35 #include "map_helpers.h"
36 #include "my_alloc.h"
37 #include "my_loglevel.h"
38 #include "my_macros.h"
39 #include "my_systime.h"
40 #include "my_thread.h"
41 #include "sql/check_stack.h"
42 #include "sql/clone_handler.h"
43 #include "sql_string.h"
44 #include "template_utils.h"
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #include <algorithm>
49 #include <list>
50 #include <map>
51 #include <new>
52 #include <queue>
53 #include <sstream>
54 #include <string>
55
56 #include "dur_prop.h"
57 #include "libbinlogevents/include/compression/base.h"
58 #include "libbinlogevents/include/compression/iterator.h"
59 #include "libbinlogevents/include/control_events.h"
60 #include "libbinlogevents/include/debug_vars.h"
61 #include "libbinlogevents/include/rows_event.h"
62 #include "libbinlogevents/include/statement_events.h"
63 #include "libbinlogevents/include/table_id.h"
64 #include "mf_wcomp.h" // wild_one, wild_many
65 #include "mutex_lock.h" // Mutex_lock
66 #include "my_base.h"
67 #include "my_bitmap.h"
68 #include "my_byteorder.h"
69 #include "my_compiler.h"
70 #include "my_dbug.h"
71 #include "my_dir.h"
72 #include "my_sqlcommand.h"
73 #include "my_stacktrace.h" // my_safe_print_system_time
74 #include "my_thread_local.h"
75 #include "mysql/components/services/log_builtins.h"
76 #include "mysql/plugin.h"
77 #include "mysql/psi/mysql_file.h"
78 #include "mysql/service_mysql_alloc.h"
79 #include "mysql/thread_type.h"
80 #include "mysqld_error.h"
81 #include "partition_info.h"
82 #include "prealloced_array.h"
83 #include "sql/binlog/global.h"
84 #include "sql/binlog/recovery.h" // binlog::Binlog_recovery
85 #include "sql/binlog/tools/iterators.h"
86 #include "sql/binlog_ostream.h"
87 #include "sql/binlog_reader.h"
88 #include "sql/create_field.h"
89 #include "sql/current_thd.h"
90 #include "sql/debug_sync.h" // DEBUG_SYNC
91 #include "sql/derror.h" // ER_THD
92 #include "sql/discrete_interval.h"
93 #include "sql/field.h"
94 #include "sql/handler.h"
95 #include "sql/item_func.h" // user_var_entry
96 #include "sql/key.h"
97 #include "sql/log.h"
98 #include "sql/log_event.h" // Rows_log_event
99 #include "sql/mysqld.h" // sync_binlog_period ...
100 #include "sql/mysqld_thd_manager.h" // Global_THD_manager
101 #include "sql/protocol.h"
102 #include "sql/psi_memory_key.h"
103 #include "sql/query_options.h"
104 #include "sql/raii/sentry.h" // raii::Sentry<>
105 #include "sql/rpl_filter.h"
106 #include "sql/rpl_gtid.h"
107 #include "sql/rpl_handler.h" // RUN_HOOK
108 #include "sql/rpl_mi.h" // Master_info
109 #include "sql/rpl_record.h"
110 #include "sql/rpl_replica.h"
111 #include "sql/rpl_replica_commit_order_manager.h" // Commit_order_manager
112 #include "sql/rpl_rli.h" // Relay_log_info
113 #include "sql/rpl_rli_pdb.h" // Slave_worker
114 #include "sql/rpl_transaction_ctx.h"
115 #include "sql/rpl_trx_boundary_parser.h" // Transaction_boundary_parser
116 #include "sql/rpl_utility.h"
117 #include "sql/sql_backup_lock.h" // is_instance_backup_locked
118 #include "sql/sql_base.h" // find_temporary_table
119 #include "sql/sql_bitmap.h"
120 #include "sql/sql_class.h" // THD
121 #include "sql/sql_const.h"
122 #include "sql/sql_data_change.h"
123 #include "sql/sql_error.h"
124 #include "sql/sql_lex.h"
125 #include "sql/sql_list.h"
126 #include "sql/sql_parse.h" // sqlcom_can_generate_row_events
127 #include "sql/sql_show.h" // append_identifier
128 #include "sql/system_variables.h"
129 #include "sql/table.h"
130 #include "sql/transaction_info.h"
131 #include "sql/xa.h"
132 #include "sql/xa/sql_cmd_xa.h" // Sql_cmd_xa_*
133 #include "sql_partition.h"
134 #include "thr_lock.h"
135
136 class Item;
137
138 using binary_log::checksum_crc32;
139 using std::list;
140
141 #ifdef WITH_WSREP
142 #include "wsrep_binlog.h"
143 #include "wsrep_trans_observer.h"
144 #include "wsrep_xid.h"
145 #endif /* WITH_WSREP */
146
147 using std::max;
148 using std::min;
149 using std::string;
150
151 #define FLAGSTR(V, F) ((V) & (F) ? #F " " : "")
152 #define YESNO(X) ((X) ? "yes" : "no")
153
154 /**
155 @defgroup Binary_Log Binary Log
156 @{
157 */
158
159 #define MY_OFF_T_UNDEF (~(my_off_t)0UL)
160
161 /*
162 Constants required for the limit unsafe warnings suppression
163 */
164 // seconds after which the limit unsafe warnings suppression will be activated
165 #define LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT 50
166 // number of limit unsafe warnings after which the suppression will be activated
167 #define LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT 50
168
169 static ulonglong limit_unsafe_suppression_start_time = 0;
170 static bool unsafe_warning_suppression_is_activated = false;
171 static int limit_unsafe_warning_count = 0;
172
173 #ifdef WITH_WSREP
174 handlerton *binlog_hton; // we need it in wsrep_binlog.cc so skip static
175 #else
176 static handlerton *binlog_hton;
177 #endif /* WITH_WSREP */
178 bool opt_binlog_order_commits = true;
179
180 const char *log_bin_index = nullptr;
181 const char *log_bin_basename = nullptr;
182
183 /* Size for IO_CACHE buffer for binlog & relay log */
184 ulong rpl_read_size;
185
186 MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period);
187
188 static int binlog_init(void *p);
189 static int binlog_start_trans_and_stmt(THD *thd, Log_event *start_event);
190 static int binlog_close_connection(handlerton *hton, THD *thd);
191 static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
192 static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
193 static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
194 THD *thd);
195 static int binlog_commit(handlerton *hton, THD *thd, bool all);
196 static int binlog_rollback(handlerton *hton, THD *thd, bool all);
197 /*
198 This function is used to prepare a transaction. For the binary log SE.
199
200 @param hton The pointer to the binlog SE plugin.
201 @param thd The THD session object holding the transaction to be prepared.
202 @param all Preparing a transaction (i.e. true) or a statement
203 (i.e. false).
204
205 @return 0 if the function is successfully executed, non-zero otherwise
206 */
207 static int binlog_prepare(handlerton *hton, THD *thd, bool all);
208 /*
209 This function is used to mark an X/Open XA distributed transaction as
210 being prepared in the server transaction coordinator.
211
212 Is a no-op function, added to the handler API to workaround warnings that
213 are triggered for SEs participating in a transaction that requires this
214 callback but such callback is not available.
215
216 @param hton The pointer to the binlog SE plugin.
217 @param thd The THD session object holding the transaction to be updated.
218
219 @return 0 if the function is successfully executed, non-zero otherwise
220 */
221 static int binlog_set_prepared_in_tc(handlerton *hton, THD *thd);
222 static void exec_binlog_error_action_abort(const char *err_string);
223 static void binlog_prepare_row_images(const THD *thd, TABLE *table);
224 static bool is_loggable_xa_prepare(THD *thd);
225 static int check_instance_backup_locked();
226
227 namespace {
228 /**
229 Finishes the transaction in the engines. If the `commit_low` flag is set,
230 will commit in the engines, otherwise, if the underlying statement is an
231 `XA ROLLBACK`, it will rollback in the engines.
232
233 @param thd The THD session object holding the transaction to finalize.
234 @param all Finalizing a transaction (i.e. true) or a statement
235 (i.e. false).
236 @param run_after_commit In the case of a commit being issued, whether or
237 not to run the `after_commit` hook.
238 */
239 void finish_transaction_in_engines(THD *thd, bool all, bool run_after_commit);
240 } // namespace
241
242 2913078 bool normalize_binlog_name(char *to, const char *from, bool is_relay_log) {
243
1/2
✓ Branch 0 taken 2913078 times.
✗ Branch 1 not taken.
2913078 DBUG_TRACE;
244 2913078 bool error = false;
245 char buff[FN_REFLEN];
246 2913078 char *ptr = const_cast<char *>(from);
247
2/2
✓ Branch 0 taken 2341145 times.
✓ Branch 1 taken 571933 times.
2913078 char *opt_name = is_relay_log ? opt_relay_logname : opt_bin_logname;
248
249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2913078 times.
2913078 assert(from);
250
251 /* opt_name is not null and not empty and from is a relative path */
252
8/12
✓ Branch 0 taken 2913078 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2913078 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2913078 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2913078 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2912873 times.
✓ Branch 9 taken 205 times.
✓ Branch 10 taken 2912873 times.
✓ Branch 11 taken 205 times.
2913078 if (opt_name && opt_name[0] && from && !test_if_hard_path(from)) {
253 // take the path from opt_name
254 // take the filename from from
255 char log_dirpart[FN_REFLEN], log_dirname[FN_REFLEN];
256 size_t log_dirpart_len, log_dirname_len;
257
1/2
✓ Branch 0 taken 2912873 times.
✗ Branch 1 not taken.
2912873 dirname_part(log_dirpart, opt_name, &log_dirpart_len);
258
1/2
✓ Branch 0 taken 2912873 times.
✗ Branch 1 not taken.
2912873 dirname_part(log_dirname, from, &log_dirname_len);
259
260 /* log may be empty => relay-log or log-bin did not
261 hold paths, just filename pattern */
262
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 2912819 times.
2912873 if (log_dirpart_len > 0) {
263 /* create the new path name */
264
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (fn_format(buff, from + log_dirname_len, log_dirpart, "",
265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH)) == nullptr) {
266 error = true;
267 goto end;
268 }
269
270 54 ptr = buff;
271 }
272 }
273
274
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2913078 times.
2913078 assert(ptr);
275
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2913078 times.
2913078 if (ptr) {
276 2913078 size_t length = strlen(ptr);
277
278 // Strips the CR+LF at the end of log name and \0-terminates it.
279
3/4
✓ Branch 0 taken 2913078 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2819660 times.
✓ Branch 3 taken 93418 times.
2913078 if (length && ptr[length - 1] == '\n') {
280 2819660 ptr[length - 1] = 0;
281 2819660 length--;
282
2/4
✓ Branch 0 taken 2819660 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2819660 times.
2819660 if (length && ptr[length - 1] == '\r') {
283 ptr[length - 1] = 0;
284 length--;
285 }
286 }
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2913078 times.
2913078 if (!length) {
288 error = true;
289 goto end;
290 }
291
1/2
✓ Branch 0 taken 2913078 times.
✗ Branch 1 not taken.
2913078 strmake(to, ptr, length);
292 }
293 end:
294 2913078 return error;
295 2913078 }
296
297 static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd);
298 static int binlog_clone_consistent_snapshot(handlerton *hton, THD *thd,
299 THD *from_thd);
300
301 ulonglong binlog_space_limit;
302
303 // The last published global binlog position
304 static char binlog_global_snapshot_file[FN_REFLEN];
305 static ulonglong binlog_global_snapshot_position;
306
307 // Binlog position variables for SHOW STATUS
308 static char binlog_snapshot_file[FN_REFLEN];
309 static ulonglong binlog_snapshot_position;
310 static std::string binlog_snapshot_gtid_executed;
311
312 static SHOW_VAR binlog_status_vars_detail[] = {
313 {"snapshot_file", (char *)&binlog_snapshot_file, SHOW_CHAR,
314 SHOW_SCOPE_GLOBAL},
315 {"snapshot_position", (char *)&binlog_snapshot_position, SHOW_LONGLONG,
316 SHOW_SCOPE_GLOBAL},
317 {NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL}};
318
319 /**
320 @brief Checks whether purge conditions are met to be able to run purge
321 for binary log files.
322
323 This function checks whether the binary log is open, if the instance
324 is not locked for backup.
325
326 @param log The reference to the binary log.
327 @return std::pair<bool, int> the first element states whether there is a
328 purge condition violation. The second element states what is the associated
329 error code, if any.
330 */
331 7109 static std::pair<bool, int> check_purge_conditions(const MYSQL_BIN_LOG &log) {
332 // is the binary log open?
333
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7107 times.
7109 if (!log.is_open()) {
334
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 return std::make_pair(true, 0);
335 }
336
337 // is instance locked for backup ?
338 7107 int error{0};
339
3/4
✓ Branch 0 taken 7107 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 7077 times.
7107 if ((error = check_instance_backup_locked()) != 0) {
340
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 return std::make_pair(true, error);
341 }
342
343 // go ahead, validations checked successfully
344
1/2
✓ Branch 0 taken 7077 times.
✗ Branch 1 not taken.
7077 return std::make_pair(false, 0);
345 }
346
347 /**
348 @brief This function abstracts the calculation of the binary log files
349 retention lower bound. It is just a function that makes it easier
350 to handle the fact that there are two mutually exclusive variables
351 that control the purge period and one of them is deprecated.
352
353 NOTE: This function and part of the purge validation functions should
354 really move to a retention policy class that abstracts the
355 retention policy altogether and its controls. Perhaps we
356 can do that once expire_logs_days is removed and a refactoring
357 is done to also include retention based on storage space
358 occupied. Then we can uses the same retention abstraction
359 for binary and relay logs and possibly extend the options
360 to retain (binary) log files not only based on time, but
361 also on space used.
362
363 @return time_t the time after which log files are considered expired.
364 */
365 31875 static time_t calculate_auto_purge_lower_time_bound() {
366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31875 times.
31875 if (DBUG_EVALUATE_IF("expire_logs_always", true, false)) return time(nullptr);
367
368
2/2
✓ Branch 0 taken 31839 times.
✓ Branch 1 taken 36 times.
31875 if (binlog_expire_logs_seconds > 0)
369 31839 return time(nullptr) - binlog_expire_logs_seconds;
370
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 else if (expire_logs_days > 0)
371 36 return time(nullptr) -
372 36 expire_logs_days * static_cast<time_t>(SECONDS_IN_24H);
373
374 // This function should only be called if binlog_expire_logs_seconds
375 // or expire_logs_days are greater than 0. In debug builds assert.
376 // In the event that on production builds there is ever a bug,
377 // that causes the caller to call this function with expire time set
378 // to 0, then do not purge - return 0 and thus file stat time is
379 // always greater than purge time.
380 assert(false); /* purecov: inspected */
381 return 0; /* purecov: inspected */
382 }
383
384 /**
385 @brief Checks if automatic purge conditions are met and therefore the
386 purge is allowed to be done. If not met returns true. Otherwise, false.
387
388 @return false if the check is successful. True otherwise.
389 */
390 15981 static bool check_auto_purge_conditions() {
391 // purge is disabled
392
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 15972 times.
15981 if (!opt_binlog_expire_logs_auto_purge) return true;
393
394 // no retention window configured
395
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 15935 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 18 times.
15972 if (binlog_expire_logs_seconds == 0 && expire_logs_days == 0) return true;
396
397 // retention window is set, but we are still within the window
398
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15952 times.
15953 if (calculate_auto_purge_lower_time_bound() < 0) return true;
399
400 // go ahead, validations checked successfully
401 15952 return false;
402 }
403
404 /**
405 Logical binlog file which wraps and hides the detail of lower layer storage
406 implementation. Binlog code just use this class to control real storage
407 */
408 class MYSQL_BIN_LOG::Binlog_ofile : public Basic_ostream {
409 public:
410 514348 ~Binlog_ofile() override {
411 257174 DBUG_TRACE;
412 257174 close();
413 257172 return;
414 514346 }
415
416 /**
417 Opens the binlog file. It opens the lower layer storage.
418
419 @param[in] log_file_key The PSI_file_key for this stream
420 @param[in] binlog_name The file to be opened
421 @param[in] flags The flags used by IO_CACHE.
422 @param[in] existing True if opening the file, false if creating a new one.
423
424 @retval false Success
425 @retval true Error
426 */
427 81761 bool open(
428 #ifdef HAVE_PSI_INTERFACE
429 PSI_file_key log_file_key,
430 #endif
431 const char *binlog_name, myf flags, bool existing = false) {
432
1/2
✓ Branch 0 taken 81761 times.
✗ Branch 1 not taken.
81761 DBUG_TRACE;
433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81761 times.
81761 assert(m_pipeline_head == nullptr);
434
435 #ifndef NDEBUG
436 {
437 #ifndef HAVE_PSI_INTERFACE
438 PSI_file_key log_file_key = PSI_NOT_INSTRUMENTED;
439 #endif
440 MY_STAT info;
441
3/4
✓ Branch 0 taken 81760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78858 times.
✓ Branch 3 taken 2902 times.
81761 if (!mysql_file_stat(log_file_key, binlog_name, &info, MYF(0))) {
442
2/4
✓ Branch 0 taken 78857 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78857 times.
78858 assert(existing == !(my_errno() == ENOENT));
443
1/2
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
78857 set_my_errno(0);
444 }
445 }
446 #endif
447
448
2/4
✓ Branch 0 taken 81760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81758 times.
✗ Branch 3 not taken.
81760 std::unique_ptr<IO_CACHE_ostream> file_ostream(new IO_CACHE_ostream);
449
2/4
✓ Branch 0 taken 81760 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 81760 times.
81760 if (file_ostream->open(log_file_key, binlog_name, flags)) return true;
450
451 81760 m_pipeline_head = std::move(file_ostream);
452
453 /* Setup encryption for new files if needed */
454
7/8
✓ Branch 0 taken 78858 times.
✓ Branch 1 taken 2902 times.
✓ Branch 2 taken 78858 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 301 times.
✓ Branch 5 taken 78557 times.
✓ Branch 6 taken 301 times.
✓ Branch 7 taken 81459 times.
81760 if (!existing && rpl_encryption.is_enabled()) {
455 std::unique_ptr<Binlog_encryption_ostream> encrypted_ostream(
456
1/2
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
301 new Binlog_encryption_ostream());
457
2/4
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 301 times.
301 if (encrypted_ostream->open(std::move(m_pipeline_head))) return true;
458
1/2
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
301 m_encrypted_header_size = encrypted_ostream->get_header_size();
459 301 m_pipeline_head = std::move(encrypted_ostream);
460
1/2
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
301 }
461
462 81760 return false;
463 81760 }
464
465 /**
466 Opens an existing binlog file. It opens the lower layer storage reusing the
467 existing file password if needed.
468
469 @param[in] log_file_key The PSI_file_key for this stream
470 @param[in] binlog_name The file to be opened
471 @param[in] flags The flags used by IO_CACHE.
472
473 @retval std::unique_ptr A Binlog_ofile object pointer.
474 @retval nullptr Error.
475 */
476 2903 static std::unique_ptr<Binlog_ofile> open_existing(
477 #ifdef HAVE_PSI_INTERFACE
478 PSI_file_key log_file_key,
479 #endif
480 const char *binlog_name, myf flags) {
481
1/2
✓ Branch 0 taken 2903 times.
✗ Branch 1 not taken.
2903 DBUG_TRACE;
482 2903 std::unique_ptr<Rpl_encryption_header> header;
483 unsigned char magic[BINLOG_MAGIC_SIZE];
484
485 /* Open a simple istream to read the magic from the file */
486
1/2
✓ Branch 0 taken 2903 times.
✗ Branch 1 not taken.
2903 IO_CACHE_istream istream;
487
3/4
✓ Branch 0 taken 2903 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2902 times.
2903 if (istream.open(key_file_binlog, key_file_binlog_cache, binlog_name,
488 MYF(MY_WME | MY_DONT_CHECK_FILESIZE), rpl_read_size))
489 1 return nullptr;
490
2/4
✓ Branch 0 taken 2902 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2902 times.
2902 if (istream.read(magic, BINLOG_MAGIC_SIZE) != BINLOG_MAGIC_SIZE)
491 return nullptr;
492
493 assert(Rpl_encryption_header::ENCRYPTION_MAGIC_SIZE == BINLOG_MAGIC_SIZE);
494 /* Identify the file type by the magic to get the encryption header */
495
2/2
✓ Branch 0 taken 1100 times.
✓ Branch 1 taken 1802 times.
2902 if (memcmp(magic, Rpl_encryption_header::ENCRYPTION_MAGIC,
496 BINLOG_MAGIC_SIZE) == 0) {
497
1/2
✓ Branch 0 taken 1100 times.
✗ Branch 1 not taken.
1100 header = Rpl_encryption_header::get_header(&istream);
498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1100 times.
1100 if (header == nullptr) return nullptr;
499
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1802 times.
1802 } else if (memcmp(magic, BINLOG_MAGIC, BINLOG_MAGIC_SIZE) != 0) {
500 return nullptr;
501 }
502
503 /* Open the binlog_ofile */
504
1/2
✓ Branch 0 taken 2902 times.
✗ Branch 1 not taken.
2902 std::unique_ptr<Binlog_ofile> ret_ofile(new Binlog_ofile);
505
2/4
✓ Branch 0 taken 2902 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2902 times.
2902 if (ret_ofile->open(
506 #ifdef HAVE_PSI_INTERFACE
507 log_file_key,
508 #endif
509 binlog_name, flags, true)) {
510 return nullptr;
511 }
512
513
2/2
✓ Branch 0 taken 1100 times.
✓ Branch 1 taken 1802 times.
2902 if (header != nullptr) {
514 /* Add the encryption stream on top of IO_CACHE */
515 std::unique_ptr<Binlog_encryption_ostream> encrypted_ostream(
516
1/2
✓ Branch 0 taken 1100 times.
✗ Branch 1 not taken.
1100 new Binlog_encryption_ostream);
517
1/2
✓ Branch 0 taken 1100 times.
✗ Branch 1 not taken.
1100 ret_ofile->m_encrypted_header_size = header->get_header_size();
518
1/2
✓ Branch 0 taken 1100 times.
✗ Branch 1 not taken.
2200 encrypted_ostream->open(std::move(ret_ofile->m_pipeline_head),
519 1100 std::move(header));
520 1100 ret_ofile->m_pipeline_head = std::move(encrypted_ostream);
521 1100 ret_ofile->set_encrypted();
522 1100 }
523 2902 return ret_ofile;
524 2903 }
525
526 205831 void close() {
527 205831 m_pipeline_head.reset(nullptr);
528 205830 m_position = 0;
529 205830 m_encrypted_header_size = 0;
530 205830 }
531
532 /**
533 Writes data into storage and maintains binlog position.
534
535 @param[in] buffer the data will be written
536 @param[in] length the length of the data
537
538 @retval false Success
539 @retval true Error
540 */
541 55156035 bool write(const unsigned char *buffer, my_off_t length) override {
542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55156026 times.
55156035 assert(m_pipeline_head != nullptr);
543
544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55156015 times.
55156026 if (m_pipeline_head->write(buffer, length)) return true;
545
546 55156015 m_position += length;
547 55156015 return false;
548 }
549
550 /**
551 Updates some bytes in the binlog file. If is only used for clearing
552 LOG_EVENT_BINLOG_IN_USE_F.
553
554 @param[in] buffer the data will be written
555 @param[in] length the length of the data
556 @param[in] offset the offset of the bytes will be updated
557
558 @retval false Success
559 @retval true Error
560 */
561 26602 bool update(const unsigned char *buffer, my_off_t length, my_off_t offset) {
562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26602 times.
26602 assert(m_pipeline_head != nullptr);
563
1/2
✓ Branch 0 taken 26602 times.
✗ Branch 1 not taken.
53204 return m_pipeline_head->seek(offset) ||
564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26602 times.
53204 m_pipeline_head->write(buffer, length);
565 }
566
567 /**
568 Truncates some data at the end of the binlog file.
569
570 @param[in] offset where the binlog file will be truncated to.
571
572 @retval false Success
573 @retval true Error
574 */
575 12 bool truncate(my_off_t offset) {
576
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(m_pipeline_head != nullptr);
577
578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (m_pipeline_head->truncate(offset)) return true;
579 12 m_position = offset;
580 12 return false;
581 }
582
583 4284951 bool flush() { return m_pipeline_head->flush(); }
584 2618327 bool sync() { return m_pipeline_head->sync(); }
585
3/4
✓ Branch 0 taken 156100 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156095 times.
156102 bool flush_and_sync() { return flush() || sync(); }
586 16209267 my_off_t position() { return m_position; }
587 78858 bool is_empty() { return position() == 0; }
588 2497490 bool is_open() { return m_pipeline_head != nullptr; }
589 /**
590 Returns the encrypted header size of the binary log file.
591
592 @retval 0 The file is not encrypted.
593 @retval >0 The encryption header size.
594 */
595 1449981 int get_encrypted_header_size() { return m_encrypted_header_size; }
596 /**
597 Returns the real file size.
598
599 While position() returns the "file size" from the plain binary log events
600 stream point of view, this function considers the encryption header when it
601 exists.
602
603 @return The real file size considering the encryption header.
604 */
605 4386051 my_off_t get_real_file_size() { return m_position + m_encrypted_header_size; }
606 /**
607 Get the pipeline head.
608
609 @retval Returns the pipeline head or nullptr.
610 */
611 1070 std::unique_ptr<Truncatable_ostream> get_pipeline_head() {
612 1070 return std::move(m_pipeline_head);
613 }
614 /**
615 Check if the log file is encrypted.
616
617 @retval True if the log file is encrypted.
618 @retval False if the log file is not encrypted.
619 */
620 1158 bool is_encrypted() { return m_encrypted; }
621 /**
622 Set that the log file is encrypted.
623 */
624 1100 void set_encrypted() { m_encrypted = true; }
625
626 private:
627 my_off_t m_position = 0;
628 int m_encrypted_header_size = 0;
629 std::unique_ptr<Truncatable_ostream> m_pipeline_head;
630 bool m_encrypted = false;
631 };
632
633 /**
634 Helper class to switch to a new thread and then go back to the previous one,
635 when the object is destroyed using RAII.
636
637 This class is used to temporarily switch to another session (THD
638 structure). It will set up thread specific "globals" correctly
639 so that the POSIX thread looks exactly like the session attached to.
640 However, PSI_thread info is not touched as it is required to show
641 the actual physical view in PFS instrumentation i.e., it should
642 depict as the real thread doing the work instead of thread it switched
643 to.
644
645 On destruction, the original session (which is supplied to the
646 constructor) will be re-attached automatically. For example, with
647 this code, the value of @c current_thd will be the same before and
648 after execution of the code.
649
650 @code
651 {
652 for (int i = 0 ; i < count ; ++i)
653 {
654 // here we are attached to current_thd
655 // [...]
656 Thd_backup_and_restore switch_thd(current_thd, other_thd[i]);
657 // [...]
658 // here we are attached to other_thd[i]
659 // [...]
660 }
661 // here we are attached to current_thd
662 }
663 @endcode
664
665 @warning The class is not designed to be inherited from.
666 */
667
668 class Thd_backup_and_restore {
669 public:
670 /**
671 Try to attach the POSIX thread to a session.
672
673 @param[in] backup_thd The thd to restore to when object is destructed.
674 @param[in] new_thd The thd to attach to.
675 */
676
677 10337180 Thd_backup_and_restore(THD *backup_thd, THD *new_thd)
678 10337180 : m_backup_thd(backup_thd),
679 10337180 m_new_thd(new_thd),
680 10337180 m_new_thd_old_real_id(new_thd->real_id),
681 10337180 m_new_thd_old_thread_stack(new_thd->thread_stack) {
682
2/4
✓ Branch 0 taken 10337195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10337195 times.
✗ Branch 3 not taken.
10337180 assert(m_backup_thd != nullptr && m_new_thd != nullptr);
683 // Reset the state of the current thd.
684 10337195 m_backup_thd->restore_globals();
685
686 10337192 m_new_thd->thread_stack = m_backup_thd->thread_stack;
687 10337192 m_new_thd->store_globals();
688 #ifdef HAVE_PSI_THREAD_INTERFACE
689 10337176 PSI_THREAD_CALL(set_mem_cnt_THD)(m_new_thd, &m_backup_cnt_thd);
690 #endif
691 10337173 }
692
693 /**
694 Restores to previous thd.
695 */
696 10337190 ~Thd_backup_and_restore() {
697 /*
698 Restore the global variables of the thd we previously attached to,
699 to its original state. In other words, detach the m_new_thd.
700 */
701 10337190 m_new_thd->restore_globals();
702 10337198 m_new_thd->real_id = m_new_thd_old_real_id;
703 10337198 m_new_thd->thread_stack = m_new_thd_old_thread_stack;
704
705 // Reset the global variables to the original state.
706 10337198 m_backup_thd->store_globals();
707 #ifdef HAVE_PSI_THREAD_INTERFACE
708 10337190 PSI_THREAD_CALL(set_mem_cnt_THD)(m_backup_cnt_thd, &m_dummy_cnt_thd);
709 #endif
710 10337190 }
711
712 private:
713 THD *m_backup_thd;
714 THD *m_new_thd;
715 THD *m_backup_cnt_thd;
716 THD *m_dummy_cnt_thd;
717 my_thread_t m_new_thd_old_real_id;
718 const char *m_new_thd_old_thread_stack;
719 };
720
721 /**
722 Caches for non-transactional and transactional data before writing
723 it to the binary log.
724
725 @todo All the access functions for the flags suggest that the
726 encapsuling is not done correctly, so try to move any logic that
727 requires access to the flags into the cache.
728 */
729 class binlog_cache_data {
730 public:
731 84058 binlog_cache_data(bool trx_cache_arg, ulong *ptr_binlog_cache_use_arg,
732 ulong *ptr_binlog_cache_disk_use_arg)
733 168116 : m_pending(nullptr),
734 84058 ptr_binlog_cache_use(ptr_binlog_cache_use_arg),
735
1/2
✓ Branch 0 taken 84058 times.
✗ Branch 1 not taken.
84058 ptr_binlog_cache_disk_use(ptr_binlog_cache_disk_use_arg) {
736 84058 flags.transactional = trx_cache_arg;
737 84058 }
738
739 84058 bool open(my_off_t cache_size, my_off_t max_cache_size) {
740 84058 return m_cache.open(cache_size, max_cache_size);
741 }
742
743 3763045 Binlog_cache_storage *get_cache() { return &m_cache; }
744 int finalize(THD *thd, Log_event *end_event);
745 int finalize(THD *thd, Log_event *end_event, XID_STATE *xs);
746 int flush(THD *thd, my_off_t *bytes, bool *wrote_xid);
747 int write_event(Log_event *event);
748 2590253 size_t get_event_counter() { return event_counter; }
749 2590011 size_t get_compressed_size() { return m_compressed_size; }
750 2590011 size_t get_decompressed_size() { return m_decompressed_size; }
751 2590011 binary_log::transaction::compression::type get_compression_type() {
752 2590011 return m_compression_type;
753 }
754
755 2590983 void set_compressed_size(size_t s) { m_compressed_size = s; }
756 2591044 void set_decompressed_size(size_t s) { m_decompressed_size = s; }
757 2590899 void set_compression_type(binary_log::transaction::compression::type t) {
758 2590899 m_compression_type = t;
759 2590899 }
760
761 163066 virtual ~binlog_cache_data() {
762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81578 times.
163066 assert(is_binlog_empty());
763 163156 m_cache.close();
764 }
765
766 60940869 bool is_binlog_empty() const {
767
4/4
✓ Branch 0 taken 3108 times.
✓ Branch 1 taken 60938916 times.
✓ Branch 2 taken 1776 times.
✓ Branch 3 taken 1332 times.
60940869 DBUG_PRINT("debug", ("%s_cache - pending: 0x%llx, bytes: %llu",
768 (flags.transactional ? "trx" : "stmt"),
769 (ulonglong)pending(), (ulonglong)m_cache.length()));
770
4/4
✓ Branch 0 taken 60789548 times.
✓ Branch 1 taken 152465 times.
✓ Branch 2 taken 40423829 times.
✓ Branch 3 taken 20367360 times.
60942024 return pending() == nullptr && m_cache.is_empty();
771 }
772
773 5393750 bool is_finalized() const { return flags.finalized; }
774
775 138079648 Rows_log_event *pending() const { return m_pending; }
776
777 8855756 void set_pending(Rows_log_event *const pending) { m_pending = pending; }
778
779 11 void set_incident(void) { flags.incident = true; }
780
781 2604513 bool has_incident(void) const { return flags.incident; }
782
783 4685252 bool has_xid() const {
784 // There should only be an XID event if we are transactional
785
5/6
✓ Branch 0 taken 2099936 times.
✓ Branch 1 taken 2585316 times.
✓ Branch 2 taken 317939 times.
✓ Branch 3 taken 1781997 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4367313 times.
4685252 assert((flags.transactional && flags.with_xid) || !flags.with_xid);
786 4685252 return flags.with_xid;
787 }
788
789 2590142 bool is_trx_cache() const { return flags.transactional; }
790
791 7450032 my_off_t get_byte_position() const { return m_cache.length(); }
792
793 15618853 void cache_state_checkpoint(my_off_t pos_to_checkpoint) {
794 // We only need to store the cache state for pos > 0
795
2/2
✓ Branch 0 taken 10721432 times.
✓ Branch 1 taken 4897421 times.
15618853 if (pos_to_checkpoint) {
796 cache_state state;
797 10721432 state.with_rbr = flags.with_rbr;
798 10721432 state.with_sbr = flags.with_sbr;
799 10721432 state.with_start = flags.with_start;
800 10721432 state.with_end = flags.with_end;
801 10721432 state.with_content = flags.with_content;
802 10721432 state.event_counter = event_counter;
803
1/2
✓ Branch 0 taken 10721330 times.
✗ Branch 1 not taken.
10721432 cache_state_map[pos_to_checkpoint] = state;
804 }
805 15618751 }
806
807 5277 void cache_state_rollback(my_off_t pos_to_rollback) {
808
2/2
✓ Branch 0 taken 4199 times.
✓ Branch 1 taken 1078 times.
5277 if (pos_to_rollback) {
809 4199 std::map<my_off_t, cache_state>::iterator it;
810
1/2
✓ Branch 0 taken 4199 times.
✗ Branch 1 not taken.
4199 it = cache_state_map.find(pos_to_rollback);
811
1/2
✓ Branch 0 taken 4199 times.
✗ Branch 1 not taken.
4199 if (it != cache_state_map.end()) {
812 4199 flags.with_rbr = it->second.with_rbr;
813 4199 flags.with_sbr = it->second.with_sbr;
814 4199 flags.with_start = it->second.with_start;
815 4199 flags.with_end = it->second.with_end;
816 4199 flags.with_content = it->second.with_content;
817 4199 event_counter = it->second.event_counter;
818 } else
819 assert(it == cache_state_map.end());
820 }
821 // Rolling back to pos == 0 means cleaning up the cache.
822 else {
823 1078 flags.with_rbr = false;
824 1078 flags.with_sbr = false;
825 1078 flags.with_start = false;
826 1078 flags.with_end = false;
827 1078 flags.with_content = false;
828 1078 event_counter = 0;
829 }
830 5277 }
831
832 /**
833 Reset the cache to unused state when the transaction is finished. It
834 drops all data in the cache and clears the flags of the transaction state.
835 */
836 2596089 virtual void reset() {
837 2596089 compute_statistics();
838 2596089 remove_pending_event();
839
840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2596089 times.
2596089 if (m_cache.reset()) {
841 LogErr(WARNING_LEVEL, ER_BINLOG_CANT_RESIZE_CACHE);
842 }
843
844 2596089 flags.incident = false;
845 2596089 flags.with_xid = false;
846 2596089 flags.immediate = false;
847 2596089 flags.finalized = false;
848 2596089 flags.with_sbr = false;
849 2596089 flags.with_rbr = false;
850 2596089 flags.with_start = false;
851 2596089 flags.with_end = false;
852 2596089 flags.with_content = false;
853
854 /*
855 The truncate function calls reinit_io_cache that calls my_b_flush_io_cache
856 which may increase disk_writes. This breaks the disk_writes use by the
857 binary log which aims to compute the ratio between in-memory cache usage
858 and disk cache usage. To avoid this undesirable behavior, we reset the
859 variable after truncating the cache.
860 */
861 2596089 cache_state_map.clear();
862 2596089 event_counter = 0;
863 2596089 m_compressed_size = 0;
864 2596089 m_decompressed_size = 0;
865 2596089 m_compression_type = binary_log::transaction::compression::NONE;
866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2596090 times.
2596089 assert(is_binlog_empty());
867 2596090 }
868
869 /**
870 Returns information about the cache content with respect to
871 the binlog_format of the events.
872
873 This will be used to set a flag on GTID_LOG_EVENT stating that the
874 transaction may have SBR statements or not, but the binlog dump
875 will show this flag as "rbr_only" when it is not set. That's why
876 an empty transaction should return true below, or else an empty
877 transaction would be assumed as "rbr_only" even not having RBR
878 events.
879
880 When dumping a binary log content using mysqlbinlog client program,
881 for any transaction assumed as "rbr_only" it will be printed a
882 statement changing the transaction isolation level to READ COMMITTED.
883 It doesn't make sense to have an empty transaction "requiring" this
884 isolation level change.
885
886 @return true The cache have SBR events or is empty.
887 @return false The cache contains a transaction with no SBR events.
888 */
889
4/4
✓ Branch 0 taken 1977516 times.
✓ Branch 1 taken 612781 times.
✓ Branch 2 taken 56331 times.
✓ Branch 3 taken 1921185 times.
2590297 bool may_have_sbr_stmts() { return flags.with_sbr || !flags.with_rbr; }
890
891 /**
892 Check if the binlog cache contains an empty transaction, which has
893 two binlog events "BEGIN" and "COMMIT".
894
895 @return true The binlog cache contains an empty transaction.
896 @return false Otherwise.
897 */
898 884 bool has_empty_transaction() {
899 /*
900 The empty transaction has two events in trx/stmt binlog cache
901 and no changes: one is a transaction start and other is a transaction
902 end (there should be no SBR changing content and no RBR events).
903 */
904
2/2
✓ Branch 0 taken 470 times.
✓ Branch 1 taken 414 times.
884 if (flags.with_start && // Has transaction start statement
905
1/2
✓ Branch 0 taken 470 times.
✗ Branch 1 not taken.
470 flags.with_end && // Has transaction end statement
906
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 460 times.
470 !flags.with_content) // Has no other content than START/END
907 {
908
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(event_counter == 2); // Two events in the cache only
909
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(!flags.with_sbr); // No statements changing content
910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(!flags.with_rbr); // No rows changing content
911
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(!flags.immediate); // Not a DDL
912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(!flags.with_xid); // Not a XID trx and not an atomic DDL Query
913 10 return true;
914 }
915 874 return false;
916 }
917
918 /**
919 Check if the binlog cache is empty or contains an empty transaction,
920 which has two binlog events "BEGIN" and "COMMIT".
921
922 @return true The binlog cache is empty or contains an empty transaction.
923 @return false Otherwise.
924 */
925 894 bool is_empty_or_has_empty_transaction() {
926
4/4
✓ Branch 0 taken 884 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 874 times.
894 return is_binlog_empty() || has_empty_transaction();
927 }
928
929 protected:
930 /*
931 This structure should have all cache variables/flags that should be restored
932 when a ROLLBACK TO SAVEPOINT statement be executed.
933 */
934 struct cache_state {
935 bool with_sbr;
936 bool with_rbr;
937 bool with_start;
938 bool with_end;
939 bool with_content;
940 size_t event_counter;
941 };
942 /*
943 For every SAVEPOINT used, we will store a cache_state for the current
944 binlog cache position. So, if a ROLLBACK TO SAVEPOINT is used, we can
945 restore the cache_state values after truncating the binlog cache.
946 */
947 std::map<my_off_t, cache_state> cache_state_map;
948 /*
949 In order to compute the transaction size (because of possible extra checksum
950 bytes), we need to keep track of how many events are in the binlog cache.
951 */
952 size_t event_counter = 0;
953
954 size_t m_compressed_size = 0;
955 size_t m_decompressed_size = 0;
956 binary_log::transaction::compression::type m_compression_type =
957 binary_log::transaction::compression::type::NONE;
958 /*
959 It truncates the cache to a certain position. This includes deleting the
960 pending event. It corresponds to rollback statement or rollback to
961 a savepoint. It doesn't change transaction state.
962 */
963 5277 void truncate(my_off_t pos) {
964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5277 times.
5277 DBUG_PRINT("info", ("truncating to position %lu", (ulong)pos));
965 5277 remove_pending_event();
966
967 // TODO: check the return value.
968 5277 (void)m_cache.truncate(pos);
969 5277 }
970
971 /**
972 Flush pending event to the cache buffer.
973 */
974 2590857 int flush_pending_event(THD *thd) {
975
2/2
✓ Branch 0 taken 22639 times.
✓ Branch 1 taken 2568218 times.
2590857 if (m_pending) {
976 22639 m_pending->set_flags(Rows_log_event::STMT_END_F);
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22639 times.
22639 if (int error = write_event(m_pending)) return error;
978 22639 thd->clear_binlog_table_maps();
979 }
980 2590915 return 0;
981 }
982
983 /**
984 Remove the pending event.
985 */
986 2610309 int remove_pending_event() {
987
2/2
✓ Branch 0 taken 23934 times.
✓ Branch 1 taken 2586375 times.
2610309 delete m_pending;
988 2610310 m_pending = nullptr;
989 2610310 return 0;
990 }
991 struct Flags {
992 /*
993 Defines if this is either a trx-cache or stmt-cache, respectively, a
994 transactional or non-transactional cache.
995 */
996 bool transactional : 1;
997
998 /*
999 This indicates that some events did not get into the cache and most likely
1000 it is corrupted.
1001 */
1002 bool incident : 1;
1003
1004 /*
1005 This indicates that the cache should be written without BEGIN/END.
1006 */
1007 bool immediate : 1;
1008
1009 /*
1010 This flag indicates that the buffer was finalized and has to be
1011 flushed to disk.
1012 */
1013 bool finalized : 1;
1014
1015 /*
1016 This indicates that either the cache contain an XID event, or it's
1017 an atomic DDL Query-log-event. In the latter case the flag is set up
1018 on the statement level, namely when the Query-log-event is cached
1019 at time the DDL transaction is not committing.
1020 The flag therefore gets reset when the cache is cleaned due to
1021 the statement rollback, e.g in case of a DDL post-caching execution
1022 error.
1023 Any statement scope flag among other things must consider its
1024 reset policy when the statement is rolled back.
1025 */
1026 bool with_xid : 1;
1027
1028 /*
1029 This indicates that the cache contain statements changing content.
1030 */
1031 bool with_sbr : 1;
1032
1033 /*
1034 This indicates that the cache contain RBR event changing content.
1035 */
1036 bool with_rbr : 1;
1037
1038 /*
1039 This indicates that the cache contain s transaction start statement.
1040 */
1041 bool with_start : 1;
1042
1043 /*
1044 This indicates that the cache contain a transaction end event.
1045 */
1046 bool with_end : 1;
1047
1048 /*
1049 This indicates that the cache contain content other than START/END.
1050 */
1051 bool with_content : 1;
1052 } flags;
1053
1054 virtual bool compress(THD *);
1055
1056 private:
1057 /*
1058 Storage for byte data. This binlog_cache_data will serialize
1059 events into bytes and put them into m_cache.
1060 */
1061 Binlog_cache_storage m_cache;
1062
1063 /*
1064 Pending binrows event. This event is the event where the rows are currently
1065 written.
1066 */
1067 Rows_log_event *m_pending;
1068
1069 /**
1070 This function computes binlog cache and disk usage.
1071 */
1072 2596089 void compute_statistics() {
1073 #ifdef WITH_WSREP
1074
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 2595781 times.
2596089 if (wsrep_emulate_bin_log) return;
1075 #endif /* WITH_WSREP */
1076
2/2
✓ Branch 0 taken 2595454 times.
✓ Branch 1 taken 328 times.
2595781 if (!is_binlog_empty()) {
1077 2595454 (*ptr_binlog_cache_use)++;
1078
2/2
✓ Branch 0 taken 53536 times.
✓ Branch 1 taken 2541917 times.
2595454 if (m_cache.disk_writes() != 0) (*ptr_binlog_cache_disk_use)++;
1079 }
1080 }
1081
1082 /*
1083 Stores a pointer to the status variable that keeps track of the in-memory
1084 cache usage. This corresponds to either
1085 . binlog_cache_use or binlog_stmt_cache_use.
1086 */
1087 ulong *ptr_binlog_cache_use;
1088
1089 /*
1090 Stores a pointer to the status variable that keeps track of the disk
1091 cache usage. This corresponds to either
1092 . binlog_cache_disk_use or binlog_stmt_cache_disk_use.
1093 */
1094 ulong *ptr_binlog_cache_disk_use;
1095
1096 binlog_cache_data &operator=(const binlog_cache_data &info);
1097 binlog_cache_data(const binlog_cache_data &info);
1098 };
1099
1100 class binlog_stmt_cache_data : public binlog_cache_data {
1101 public:
1102 42029 binlog_stmt_cache_data(bool trx_cache_arg, ulong *ptr_binlog_cache_use_arg,
1103 ulong *ptr_binlog_cache_disk_use_arg)
1104 42029 : binlog_cache_data(trx_cache_arg, ptr_binlog_cache_use_arg,
1105 42029 ptr_binlog_cache_disk_use_arg) {}
1106
1107 using binlog_cache_data::finalize;
1108
1109 int finalize(THD *thd);
1110 };
1111
1112 489853 int binlog_stmt_cache_data::finalize(THD *thd) {
1113
2/2
✓ Branch 0 taken 91289 times.
✓ Branch 1 taken 398564 times.
489853 if (flags.immediate) {
1114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91290 times.
91289 if (int error = finalize(thd, nullptr)) return error;
1115 } else {
1116 Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"), false, false, true,
1117
1/2
✓ Branch 0 taken 398815 times.
✗ Branch 1 not taken.
398564 0, true);
1118
2/4
✓ Branch 0 taken 398835 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 398835 times.
398815 if (int error = finalize(thd, &end_evt)) return error;
1119
1/2
✓ Branch 0 taken 398827 times.
✗ Branch 1 not taken.
398835 }
1120 490117 return 0;
1121 }
1122
1123 class binlog_trx_cache_data : public binlog_cache_data {
1124 public:
1125 42029 binlog_trx_cache_data(bool trx_cache_arg, ulong *ptr_binlog_cache_use_arg,
1126 ulong *ptr_binlog_cache_disk_use_arg)
1127 42029 : binlog_cache_data(trx_cache_arg, ptr_binlog_cache_use_arg,
1128 ptr_binlog_cache_disk_use_arg),
1129 42029 m_cannot_rollback(false),
1130 42029 before_stmt_pos(MY_OFF_T_UNDEF) {}
1131
1132 2105863 void reset() override {
1133
1/2
✓ Branch 0 taken 2105864 times.
✗ Branch 1 not taken.
2105863 DBUG_TRACE;
1134
5/8
✓ Branch 0 taken 2105864 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2105864 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 2105780 times.
✓ Branch 6 taken 84 times.
✗ Branch 7 not taken.
2105864 DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1135 2105864 m_cannot_rollback = false;
1136 2105864 before_stmt_pos = MY_OFF_T_UNDEF;
1137
1/2
✓ Branch 0 taken 2105864 times.
✗ Branch 1 not taken.
2105864 binlog_cache_data::reset();
1138
5/8
✓ Branch 0 taken 2105864 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2105864 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 2105780 times.
✓ Branch 6 taken 84 times.
✗ Branch 7 not taken.
2105864 DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1139 4211728 return;
1140 2105864 }
1141
1142 13274 bool cannot_rollback() const { return m_cannot_rollback; }
1143
1144 1184 void set_cannot_rollback() { m_cannot_rollback = true; }
1145
1146 4906875 my_off_t get_prev_position() const { return before_stmt_pos; }
1147
1148 10758446 void set_prev_position(my_off_t pos) {
1149
1/2
✓ Branch 0 taken 10759046 times.
✗ Branch 1 not taken.
10758446 DBUG_TRACE;
1150
5/8
✓ Branch 0 taken 10758938 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10758927 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 242 times.
✓ Branch 5 taken 10758685 times.
✓ Branch 6 taken 242 times.
✗ Branch 7 not taken.
10759046 DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1151 10758927 before_stmt_pos = pos;
1152
1/2
✓ Branch 0 taken 10758864 times.
✗ Branch 1 not taken.
10758927 cache_state_checkpoint(before_stmt_pos);
1153
5/8
✓ Branch 0 taken 10758516 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10758767 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 242 times.
✓ Branch 5 taken 10758525 times.
✓ Branch 6 taken 246 times.
✗ Branch 7 not taken.
10758864 DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1154 21517844 return;
1155 10758771 }
1156
1157 1242 void restore_prev_position() {
1158
1/2
✓ Branch 0 taken 1242 times.
✗ Branch 1 not taken.
1242 DBUG_TRACE;
1159
3/8
✓ Branch 0 taken 1242 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1242 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1242 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1242 DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1160
1/2
✓ Branch 0 taken 1242 times.
✗ Branch 1 not taken.
1242 binlog_cache_data::truncate(before_stmt_pos);
1161
1/2
✓ Branch 0 taken 1242 times.
✗ Branch 1 not taken.
1242 cache_state_rollback(before_stmt_pos);
1162 1242 before_stmt_pos = MY_OFF_T_UNDEF;
1163 /*
1164 Binlog statement rollback clears with_xid now as the atomic DDL statement
1165 marker which can be set as early as at event creation and caching.
1166 */
1167 1242 flags.with_xid = false;
1168
3/8
✓ Branch 0 taken 1242 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1242 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1242 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1242 DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1169 2484 return;
1170 1242 }
1171
1172 4035 void restore_savepoint(my_off_t pos) {
1173
1/2
✓ Branch 0 taken 4035 times.
✗ Branch 1 not taken.
4035 DBUG_TRACE;
1174
3/8
✓ Branch 0 taken 4035 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4035 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4035 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4035 DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1175
1/2
✓ Branch 0 taken 4035 times.
✗ Branch 1 not taken.
4035 binlog_cache_data::truncate(pos);
1176
2/2
✓ Branch 0 taken 4019 times.
✓ Branch 1 taken 16 times.
4035 if (pos <= before_stmt_pos) before_stmt_pos = MY_OFF_T_UNDEF;
1177
1/2
✓ Branch 0 taken 4035 times.
✗ Branch 1 not taken.
4035 cache_state_rollback(pos);
1178
3/8
✓ Branch 0 taken 4035 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4035 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4035 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4035 DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1179 8070 return;
1180 4035 }
1181
1182 using binlog_cache_data::truncate;
1183
1184 int truncate(THD *thd, bool all);
1185
1186 private:
1187 /*
1188 It will be set true if any statement which cannot be rolled back safely
1189 is put in trx_cache.
1190 */
1191 bool m_cannot_rollback;
1192
1193 /*
1194 Binlog position before the start of the current statement.
1195 */
1196 my_off_t before_stmt_pos;
1197
1198 binlog_trx_cache_data &operator=(const binlog_trx_cache_data &info);
1199 binlog_trx_cache_data(const binlog_trx_cache_data &info);
1200 };
1201
1202 class binlog_cache_mngr {
1203 public:
1204 42029 binlog_cache_mngr(ulong *ptr_binlog_stmt_cache_use_arg,
1205 ulong *ptr_binlog_stmt_cache_disk_use_arg,
1206 ulong *ptr_binlog_cache_use_arg,
1207 ulong *ptr_binlog_cache_disk_use_arg)
1208 42029 : stmt_cache(false, ptr_binlog_stmt_cache_use_arg,
1209 ptr_binlog_stmt_cache_disk_use_arg),
1210
1/2
✓ Branch 0 taken 42029 times.
✗ Branch 1 not taken.
42029 trx_cache(true, ptr_binlog_cache_use_arg,
1211 42029 ptr_binlog_cache_disk_use_arg) {}
1212
1213 42027 bool init() {
1214 42027 return stmt_cache.open(binlog_stmt_cache_size,
1215
1/2
✓ Branch 0 taken 42029 times.
✗ Branch 1 not taken.
84058 max_binlog_stmt_cache_size) ||
1216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42029 times.
84058 trx_cache.open(binlog_cache_size, max_binlog_cache_size);
1217 }
1218
1219 89656105 binlog_cache_data *get_binlog_cache_data(bool is_transactional) {
1220
2/2
✓ Branch 0 taken 76558748 times.
✓ Branch 1 taken 13097357 times.
89656105 if (is_transactional)
1221 76558748 return &trx_cache;
1222 else
1223 13097357 return &stmt_cache;
1224 }
1225
1226 103745 Binlog_cache_storage *get_stmt_cache() { return stmt_cache.get_cache(); }
1227 1069349 Binlog_cache_storage *get_trx_cache() { return trx_cache.get_cache(); }
1228 /**
1229 Convenience method to check if both caches are empty.
1230 */
1231 310112 bool is_binlog_empty() const {
1232
4/4
✓ Branch 0 taken 309383 times.
✓ Branch 1 taken 834 times.
✓ Branch 2 taken 300591 times.
✓ Branch 3 taken 8795 times.
310112 return stmt_cache.is_binlog_empty() && trx_cache.is_binlog_empty();
1233 }
1234
1235 /*
1236 clear stmt_cache and trx_cache if they are not empty
1237 */
1238 912 void reset() {
1239
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 910 times.
912 if (!stmt_cache.is_binlog_empty()) stmt_cache.reset();
1240
2/2
✓ Branch 0 taken 896 times.
✓ Branch 1 taken 16 times.
912 if (!trx_cache.is_binlog_empty()) trx_cache.reset();
1241 912 }
1242
1243 #ifndef NDEBUG
1244 2697198 bool dbug_any_finalized() const {
1245
3/4
✓ Branch 0 taken 2697408 times.
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2697175 times.
2697198 return stmt_cache.is_finalized() || trx_cache.is_finalized();
1246 }
1247 #endif
1248
1249 /*
1250 Convenience method to flush both caches to the binary log.
1251
1252 @param bytes_written Pointer to variable that will be set to the
1253 number of bytes written for the flush.
1254 @param wrote_xid Pointer to variable that will be set to @c
1255 true if any XID event was written to the
1256 binary log. Otherwise, the variable will not
1257 be touched.
1258 @return Error code on error, zero if no error.
1259 */
1260 2585324 int flush(THD *thd, my_off_t *bytes_written, bool *wrote_xid) {
1261 2585324 my_off_t stmt_bytes = 0;
1262 2585324 my_off_t trx_bytes = 0;
1263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2585324 times.
2585324 assert(stmt_cache.has_xid() == 0);
1264
1/2
✓ Branch 0 taken 2585323 times.
✗ Branch 1 not taken.
2585324 int error = stmt_cache.flush(thd, &stmt_bytes, wrote_xid);
1265
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2585322 times.
2585323 if (error) return error;
1266
3/4
✓ Branch 0 taken 2584042 times.
✓ Branch 1 taken 1280 times.
✓ Branch 2 taken 2584042 times.
✗ Branch 3 not taken.
2585322 DEBUG_SYNC(thd, "after_flush_stm_cache_before_flush_trx_cache");
1267
1/2
✓ Branch 0 taken 2585320 times.
✗ Branch 1 not taken.
2585322 error = trx_cache.flush(thd, &trx_bytes, wrote_xid);
1268
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2585317 times.
2585320 if (error) return error;
1269 2585317 *bytes_written = stmt_bytes + trx_bytes;
1270 2585317 return 0;
1271 }
1272
1273 /**
1274 Check if at least one of transactions and statement binlog caches
1275 contains an empty transaction, other one is empty or contains an
1276 empty transaction.
1277
1278 @return true At least one of transactions and statement binlog
1279 caches an empty transaction, other one is empty
1280 or contains an empty transaction.
1281 @return false Otherwise.
1282 */
1283 884 bool has_empty_transaction() {
1284 884 return (trx_cache.is_empty_or_has_empty_transaction() &&
1285
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 874 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
894 stmt_cache.is_empty_or_has_empty_transaction() &&
1286
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
894 !is_binlog_empty());
1287 }
1288
1289 /**
1290 Check if manager contains consistent snapshot of log coordinates
1291 and gtid_executed.
1292
1293 @return true Consistent snapshot available
1294 @return false Otherwise
1295 */
1296 39058 bool has_consistent_snapshot() const {
1297 /**
1298 snapshot_gtid_executed can be empty string
1299 if gtid_mode=OFF.
1300 */
1301
1302 39058 return binlog_info.log_file_name[0] != '\0';
1303 }
1304
1305 /**
1306 Removes consistent snapshot from cache.
1307 */
1308 2260523 void drop_consistent_snapshot() {
1309 2260523 binlog_info.log_file_name[0] = '\0';
1310 2260523 snapshot_gtid_executed.clear();
1311 2260719 }
1312
1313 binlog_stmt_cache_data stmt_cache;
1314 binlog_trx_cache_data trx_cache;
1315
1316 LOG_INFO binlog_info;
1317 std::string snapshot_gtid_executed;
1318
1319 private:
1320 binlog_cache_mngr &operator=(const binlog_cache_mngr &info);
1321 binlog_cache_mngr(const binlog_cache_mngr &info);
1322 };
1323
1324 191516325 static binlog_cache_mngr *thd_get_cache_mngr(const THD *thd) {
1325 /*
1326 If opt_bin_log is not set, binlog_hton->slot == -1 and hence
1327 thd_get_ha_data(thd, hton) segfaults.
1328 */
1329 #ifdef WITH_WSREP
1330 /* PXC can operate in emulation bin logging mode so suppressing the check. */
1331 #else
1332 assert(opt_bin_log);
1333 #endif /* WITH_WSREP */
1334 191516325 return (binlog_cache_mngr *)thd_get_ha_data(thd, binlog_hton);
1335 }
1336
1337 /**
1338 Checks if the BINLOG_CACHE_SIZE's value is greater than MAX_BINLOG_CACHE_SIZE.
1339 If this happens, the BINLOG_CACHE_SIZE is set to MAX_BINLOG_CACHE_SIZE.
1340 */
1341 9488 void check_binlog_cache_size(THD *thd) {
1342
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 9474 times.
9488 if (binlog_cache_size > max_binlog_cache_size) {
1343
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
14 if (thd) {
1344 12 push_warning_printf(
1345 thd, Sql_condition::SL_WARNING, ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX,
1346 ER_THD(thd, ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX),
1347 (ulong)binlog_cache_size, (ulong)max_binlog_cache_size);
1348 } else {
1349
7/14
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
2 LogErr(WARNING_LEVEL, ER_BINLOG_CACHE_SIZE_TOO_LARGE, binlog_cache_size,
1350 (ulong)max_binlog_cache_size);
1351 }
1352 14 binlog_cache_size = static_cast<ulong>(max_binlog_cache_size);
1353 }
1354 9488 }
1355
1356 /**
1357 Checks if the BINLOG_STMT_CACHE_SIZE's value is greater than
1358 MAX_BINLOG_STMT_CACHE_SIZE. If this happens, the BINLOG_STMT_CACHE_SIZE is set
1359 to MAX_BINLOG_STMT_CACHE_SIZE.
1360 */
1361 9464 void check_binlog_stmt_cache_size(THD *thd) {
1362
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9455 times.
9464 if (binlog_stmt_cache_size > max_binlog_stmt_cache_size) {
1363
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (thd) {
1364 9 push_warning_printf(
1365 thd, Sql_condition::SL_WARNING,
1366 ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX,
1367 ER_THD(thd, ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX),
1368 (ulong)binlog_stmt_cache_size, (ulong)max_binlog_stmt_cache_size);
1369 } else {
1370 LogErr(WARNING_LEVEL, ER_BINLOG_STMT_CACHE_SIZE_TOO_LARGE,
1371 binlog_stmt_cache_size, (ulong)max_binlog_stmt_cache_size);
1372 }
1373 9 binlog_stmt_cache_size = static_cast<ulong>(max_binlog_stmt_cache_size);
1374 }
1375 9464 }
1376
1377 /**
1378 Check whether binlog_hton has valid slot and enabled
1379 */
1380 bool binlog_enabled() {
1381 return (binlog_hton && binlog_hton->slot != HA_SLOT_UNDEF);
1382 }
1383
1384 /*
1385 Save position of binary log transaction cache.
1386
1387 SYNPOSIS
1388 binlog_trans_log_savepos()
1389
1390 thd The thread to take the binlog data from
1391 pos Pointer to variable where the position will be stored
1392
1393 DESCRIPTION
1394
1395 Save the current position in the binary log transaction cache into
1396 the variable pointed to by 'pos'
1397 */
1398
1399 4859783 static void binlog_trans_log_savepos(THD *thd, my_off_t *pos) {
1400
1/2
✓ Branch 0 taken 4860223 times.
✗ Branch 1 not taken.
4859783 DBUG_TRACE;
1401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4860223 times.
4860223 assert(pos != nullptr);
1402
1/2
✓ Branch 0 taken 4860328 times.
✗ Branch 1 not taken.
4860223 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
1403
1404 #ifdef WITH_WSREP
1405
10/12
✓ Branch 0 taken 4860330 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87944 times.
✓ Branch 3 taken 4772386 times.
✓ Branch 4 taken 87930 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 87877 times.
✓ Branch 7 taken 53 times.
✓ Branch 8 taken 59 times.
✓ Branch 9 taken 87818 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 4860099 times.
4860328 assert((WSREP_EMULATE_BINLOG(thd)) || mysql_bin_log.is_open());
1406 #else
1407 assert(mysql_bin_log.is_open());
1408 #endif /* WITH_WSREP */
1409
1410
1/2
✓ Branch 0 taken 4860023 times.
✗ Branch 1 not taken.
4860158 *pos = cache_mngr->trx_cache.get_byte_position();
1411
5/8
✓ Branch 0 taken 4859926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4860008 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 95 times.
✓ Branch 5 taken 4859913 times.
✓ Branch 6 taken 95 times.
✗ Branch 7 not taken.
4860023 DBUG_PRINT("return", ("position: %lu", (ulong)*pos));
1412
1/2
✓ Branch 0 taken 4859968 times.
✗ Branch 1 not taken.
4860008 cache_mngr->trx_cache.cache_state_checkpoint(*pos);
1413 4859968 }
1414
1415 9292 static int binlog_dummy_recover(handlerton *, XA_recover_txn *, uint,
1416 MEM_ROOT *) {
1417 9292 return 0;
1418 }
1419
1420 /**
1421 Auxiliary class to copy serialized events to the binary log and
1422 correct some of the fields that are not known until just before
1423 writing the event.
1424
1425 This class allows feeding events in parts, so it is practical to use
1426 in do_write_cache() which reads events from an IO_CACHE where events
1427 may span multiple cache pages.
1428
1429 The following fields are fixed before writing the event:
1430 - end_log_pos is set
1431 - the checksum is computed if checksums are enabled
1432 - the length is incremented by the checksum size if checksums are enabled
1433 */
1434 class Binlog_event_writer : public Basic_ostream {
1435 MYSQL_BIN_LOG::Binlog_ofile *m_binlog_file;
1436 bool have_checksum;
1437 ha_checksum initial_checksum;
1438 ha_checksum checksum;
1439 uint32 end_log_pos;
1440 THD *thd;
1441 uchar header[LOG_EVENT_HEADER_LEN];
1442 my_off_t header_len = 0;
1443 uint32 event_len = 0;
1444
1445 public:
1446 /**
1447 Constructs a new Binlog_event_writer. Should be called once before
1448 starting to flush the transaction or statement cache to the
1449 binlog.
1450
1451 @param binlog_file to write to.
1452 @param thd_arg THD to account written binlog byte statistics to
1453 */
1454 2590143 Binlog_event_writer(MYSQL_BIN_LOG::Binlog_ofile *binlog_file, THD *thd_arg)
1455 5180286 : m_binlog_file(binlog_file),
1456 2590143 have_checksum(binlog_checksum_options !=
1457 binary_log::BINLOG_CHECKSUM_ALG_OFF),
1458 5180286 initial_checksum(my_checksum(0L, nullptr, 0)),
1459 2590143 checksum(initial_checksum),
1460 2590143 end_log_pos(binlog_file->position()),
1461
1/2
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
2590143 thd(thd_arg) {
1462 // Simulate checksum error
1463
3/4
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2590142 times.
2590143 if (DBUG_EVALUATE_IF("fault_injection_crc_value", 1, 0)) checksum--;
1464 2590143 }
1465
1466 16491695 void update_header() {
1467 16491695 event_len = uint4korr(header + EVENT_LEN_OFFSET);
1468
1469 // Increase end_log_pos
1470 16491695 end_log_pos += event_len;
1471
1472 // Update event length if it has checksum
1473
2/2
✓ Branch 0 taken 16490958 times.
✓ Branch 1 taken 737 times.
16491695 if (have_checksum) {
1474 16490958 int4store(header + EVENT_LEN_OFFSET, event_len + BINLOG_CHECKSUM_LEN);
1475 16490958 end_log_pos += BINLOG_CHECKSUM_LEN;
1476 }
1477
1478 // Store end_log_pos
1479 16491695 int4store(header + LOG_POS_OFFSET, end_log_pos);
1480 // update the checksum
1481
2/2
✓ Branch 0 taken 16490958 times.
✓ Branch 1 taken 737 times.
16491695 if (have_checksum) checksum = my_checksum(checksum, header, header_len);
1482 16491695 }
1483
1484 11144778 bool write(const unsigned char *buffer, my_off_t length) override {
1485
1/2
✓ Branch 0 taken 11144778 times.
✗ Branch 1 not taken.
11144778 DBUG_TRACE;
1486
1487
2/2
✓ Branch 0 taken 36357669 times.
✓ Branch 1 taken 11144778 times.
47502447 while (length > 0) {
1488 /* Write event header into binlog */
1489
2/2
✓ Branch 0 taken 16494507 times.
✓ Branch 1 taken 19863162 times.
36357669 if (event_len == 0) {
1490 /* data in the buf may be smaller than header size.*/
1491 uint32 header_incr =
1492 16494507 std::min<uint32>(LOG_EVENT_HEADER_LEN - header_len, length);
1493
1494 16494507 memcpy(header + header_len, buffer, header_incr);
1495 16494507 header_len += header_incr;
1496 16494507 buffer += header_incr;
1497 16494507 length -= header_incr;
1498
1499
2/2
✓ Branch 0 taken 16491695 times.
✓ Branch 1 taken 2812 times.
16494507 if (header_len == LOG_EVENT_HEADER_LEN) {
1500
1/2
✓ Branch 0 taken 16491695 times.
✗ Branch 1 not taken.
16491695 update_header();
1501
2/4
✓ Branch 0 taken 16491695 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16491695 times.
16491695 if (m_binlog_file->write(header, header_len)) return true;
1502
1503 16491695 event_len -= header_len;
1504 16491695 header_len = 0;
1505 }
1506 } else {
1507 19863162 my_off_t write_bytes = std::min<uint64>(length, event_len);
1508
1509
2/4
✓ Branch 0 taken 19863162 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19863162 times.
19863162 if (m_binlog_file->write(buffer, write_bytes)) return true;
1510
1511 // update the checksum
1512
2/2
✓ Branch 0 taken 19862212 times.
✓ Branch 1 taken 950 times.
19863162 if (have_checksum)
1513
1/2
✓ Branch 0 taken 19862212 times.
✗ Branch 1 not taken.
19862212 checksum = my_checksum(checksum, buffer, write_bytes);
1514
1515 19863162 event_len -= write_bytes;
1516 19863162 length -= write_bytes;
1517 19863162 buffer += write_bytes;
1518
1519 // The whole event is copied, now add the checksum
1520
4/4
✓ Branch 0 taken 19862212 times.
✓ Branch 1 taken 950 times.
✓ Branch 2 taken 16490958 times.
✓ Branch 3 taken 3371254 times.
19863162 if (have_checksum && event_len == 0) {
1521 uchar checksum_buf[BINLOG_CHECKSUM_LEN];
1522
1523 16490958 int4store(checksum_buf, checksum);
1524
2/4
✓ Branch 0 taken 16490958 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16490958 times.
16490958 if (m_binlog_file->write(checksum_buf, BINLOG_CHECKSUM_LEN))
1525 return true;
1526 16490958 checksum = initial_checksum;
1527 }
1528 }
1529 }
1530 11144778 return false;
1531 11144778 }
1532 /**
1533 Returns true if per event checksum is enabled.
1534 */
1535 2590253 bool is_checksum_enabled() { return have_checksum; }
1536 };
1537
1538 /*
1539 this function is mostly a placeholder.
1540 conceptually, binlog initialization (now mostly done in MYSQL_BIN_LOG::open)
1541 should be moved here.
1542 */
1543
1544 9606 static int binlog_init(void *p) {
1545 9606 binlog_hton = (handlerton *)p;
1546
1547 #ifdef WITH_WSREP
1548 /*
1549 During bootstrap (seed-db creation), wsrep options may not be configured
1550 which will then disable binlog_hton but other WSREP compiled checks needs
1551 binlog_hton, so enable it while operating in bootstrap mode too.
1552 */
1553
6/6
✓ Branch 0 taken 9404 times.
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 8952 times.
✓ Branch 3 taken 452 times.
✓ Branch 4 taken 202 times.
✓ Branch 5 taken 8952 times.
9606 if (WSREP_ON || opt_initialize)
1554 654 binlog_hton->state = SHOW_OPTION_YES;
1555 else
1556
2/2
✓ Branch 0 taken 8700 times.
✓ Branch 1 taken 252 times.
8952 binlog_hton->state = opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
1557 #else
1558 binlog_hton->state = opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
1559 #endif /* WITH_WSREP */
1560
1561 9606 binlog_hton->db_type = DB_TYPE_BINLOG;
1562 9606 binlog_hton->savepoint_offset = sizeof(my_off_t);
1563 9606 binlog_hton->close_connection = binlog_close_connection;
1564 9606 binlog_hton->savepoint_set = binlog_savepoint_set;
1565 9606 binlog_hton->savepoint_rollback = binlog_savepoint_rollback;
1566 9606 binlog_hton->savepoint_rollback_can_release_mdl =
1567 binlog_savepoint_rollback_can_release_mdl;
1568 9606 binlog_hton->commit = binlog_commit;
1569 9606 binlog_hton->rollback = binlog_rollback;
1570 9606 binlog_hton->prepare = binlog_prepare;
1571 9606 binlog_hton->start_consistent_snapshot = binlog_start_consistent_snapshot;
1572 9606 binlog_hton->clone_consistent_snapshot = binlog_clone_consistent_snapshot;
1573 9606 binlog_hton->set_prepared_in_tc = binlog_set_prepared_in_tc;
1574 9606 binlog_hton->recover = binlog_dummy_recover;
1575 9606 binlog_hton->flags = HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
1576 9606 return 0;
1577 }
1578
1579 8252 static int binlog_deinit(void *) {
1580 /* Using binlog as TC after the binlog has been unloaded, won't work */
1581
2/2
✓ Branch 0 taken 7864 times.
✓ Branch 1 taken 388 times.
8252 if (tc_log == &mysql_bin_log) tc_log = nullptr;
1582 8252 binlog_hton = nullptr;
1583 8252 return 0;
1584 }
1585
1586 40792 static int binlog_close_connection(handlerton *, THD *thd) {
1587
1/2
✓ Branch 0 taken 40796 times.
✗ Branch 1 not taken.
40792 DBUG_TRACE;
1588
1/2
✓ Branch 0 taken 40796 times.
✗ Branch 1 not taken.
40796 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
1589
1590 #ifdef WITH_WSREP
1591
2/4
✓ Branch 0 taken 40797 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40797 times.
40796 if (!cache_mngr->is_binlog_empty()) {
1592 /* binlog should be empty during close connection. pending binlog represent
1593 node was shutdown with replication leftover. */
1594 uchar *buf;
1595 size_t len = 0;
1596
1597 IO_CACHE_binlog_cache_storage *trx_cache = wsrep_get_trans_cache(thd, true);
1598 wsrep_write_cache_buf(trx_cache, &buf, &len);
1599 WSREP_WARN(
1600 "binlog trx cache not empty (%llu bytes) @ connection close %llu",
1601 (unsigned long long)len, (unsigned long long)thd->thread_id());
1602 if (len > 0) wsrep_dump_rbr_buf(thd, buf, len);
1603
1604 IO_CACHE_binlog_cache_storage *stmt_cache =
1605 wsrep_get_trans_cache(thd, false);
1606 wsrep_write_cache_buf(stmt_cache, &buf, &len);
1607 WSREP_WARN(
1608 "binlog stmt cache not empty (%llu bytes) @ connection close %llu",
1609 (unsigned long long)len, (unsigned long long)thd->thread_id());
1610 if (len > 0) wsrep_dump_rbr_buf(thd, buf, len);
1611 }
1612 #endif /* WITH_WSREP */
1613
1614
2/4
✓ Branch 0 taken 40774 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40774 times.
40797 assert(cache_mngr->is_binlog_empty());
1615
5/8
✓ Branch 0 taken 40795 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40793 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 40791 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
40774 DBUG_PRINT("debug", ("Set ha_data slot %d to 0x%llx", binlog_hton->slot,
1616 (ulonglong) nullptr));
1617
1/2
✓ Branch 0 taken 40797 times.
✗ Branch 1 not taken.
40793 thd_set_ha_data(thd, binlog_hton, nullptr);
1618 40797 cache_mngr->~binlog_cache_mngr();
1619
1/2
✓ Branch 0 taken 40796 times.
✗ Branch 1 not taken.
40793 my_free(cache_mngr);
1620 40791 return 0;
1621 40796 }
1622
1623 14511095 int binlog_cache_data::write_event(Log_event *ev) {
1624
1/2
✓ Branch 0 taken 14512417 times.
✗ Branch 1 not taken.
14511095 DBUG_TRACE;
1625
1626
2/2
✓ Branch 0 taken 14103199 times.
✓ Branch 1 taken 409218 times.
14512417 if (ev != nullptr) {
1627
2/6
✓ Branch 0 taken 14102830 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14102830 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
14103199 DBUG_EXECUTE_IF("simulate_disk_full_at_flush_pending",
1628 { DBUG_SET("+d,simulate_file_write_error"); });
1629
1630
3/4
✓ Branch 0 taken 14103410 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 14103332 times.
14102830 if (binary_event_serialize(ev, &m_cache)) {
1631
2/10
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
78 DBUG_EXECUTE_IF("simulate_disk_full_at_flush_pending", {
1632 DBUG_SET("-d,simulate_file_write_error");
1633 DBUG_SET("-d,simulate_disk_full_at_flush_pending");
1634 /*
1635 after +d,simulate_file_write_error the local cache
1636 is in unsane state. Since -d,simulate_file_write_error
1637 revokes the first simulation do_write_cache()
1638 can't be run without facing an assert.
1639 So it's blocked with the following 2nd simulation:
1640 */
1641 DBUG_SET("+d,simulate_do_write_cache_failure");
1642 });
1643 78 return 1;
1644 }
1645
6/6
✓ Branch 0 taken 12381032 times.
✓ Branch 1 taken 1722028 times.
✓ Branch 2 taken 627 times.
✓ Branch 3 taken 12380475 times.
✓ Branch 4 taken 1722655 times.
✓ Branch 5 taken 12380475 times.
26484434 if (ev->get_type_code() == binary_log::XID_EVENT ||
1646 12381032 ev->get_type_code() == binary_log::XA_PREPARE_LOG_EVENT)
1647 1722655 flags.with_xid = true;
1648
2/2
✓ Branch 0 taken 91511 times.
✓ Branch 1 taken 14011672 times.
14103130 if (ev->is_using_immediate_logging()) flags.immediate = true;
1649 /* DDL gets marked as xid-requiring at its caching. */
1650
2/2
✓ Branch 0 taken 317991 times.
✓ Branch 1 taken 13785262 times.
14103183 if (is_atomic_ddl_event(ev)) flags.with_xid = true;
1651 /* With respect to the event type being written */
1652
3/4
✓ Branch 0 taken 14103244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 832137 times.
✓ Branch 3 taken 13271107 times.
14103253 if (ev->is_sbr_logging_format()) flags.with_sbr = true;
1653
3/4
✓ Branch 0 taken 14102744 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8887389 times.
✓ Branch 3 taken 5215355 times.
14103244 if (ev->is_rbr_logging_format()) flags.with_rbr = true;
1654 /* With respect to empty transactions */
1655
3/4
✓ Branch 0 taken 14102768 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2187011 times.
✓ Branch 3 taken 11915757 times.
14102744 if (ev->starts_group()) flags.with_start = true;
1656
3/4
✓ Branch 0 taken 14103160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2182181 times.
✓ Branch 3 taken 11920979 times.
14102768 if (ev->ends_group()) flags.with_end = true;
1657
8/10
✓ Branch 0 taken 14103279 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11916063 times.
✓ Branch 3 taken 2187216 times.
✓ Branch 4 taken 11916066 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9733920 times.
✓ Branch 7 taken 2182146 times.
✓ Branch 8 taken 9733929 times.
✓ Branch 9 taken 4369353 times.
14103160 if (!ev->starts_group() && !ev->ends_group()) flags.with_content = true;
1658 14103282 event_counter++;
1659
5/8
✓ Branch 0 taken 14102771 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14102817 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 176 times.
✓ Branch 5 taken 14102641 times.
✓ Branch 6 taken 198 times.
✗ Branch 7 not taken.
14103282 DBUG_PRINT("debug",
1660 ("event_counter= %lu", static_cast<ulong>(event_counter)));
1661 }
1662 14512057 return 0;
1663 14512135 }
1664
1665 2494619 bool MYSQL_BIN_LOG::assign_automatic_gtids_to_flush_group(THD *first_seen) {
1666
1/2
✓ Branch 0 taken 2494619 times.
✗ Branch 1 not taken.
2494619 DBUG_TRACE;
1667 2494619 bool error = false;
1668 2494619 bool is_global_sid_locked = false;
1669 2494619 rpl_sidno locked_sidno = 0;
1670
1671
2/2
✓ Branch 0 taken 2585324 times.
✓ Branch 1 taken 2494619 times.
5079943 for (THD *head = first_seen; head; head = head->next_to_commit) {
1672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2585324 times.
2585324 assert(head->variables.gtid_next.type != UNDEFINED_GTID);
1673
1674 /* Generate GTID */
1675
2/2
✓ Branch 0 taken 2273152 times.
✓ Branch 1 taken 312172 times.
2585324 if (head->variables.gtid_next.type == AUTOMATIC_GTID) {
1676
2/2
✓ Branch 0 taken 2202278 times.
✓ Branch 1 taken 70874 times.
2273152 if (!is_global_sid_locked) {
1677
1/2
✓ Branch 0 taken 2202278 times.
✗ Branch 1 not taken.
2202278 global_sid_lock->rdlock();
1678 2202278 is_global_sid_locked = true;
1679 }
1680
3/6
✓ Branch 0 taken 2273152 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2273152 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2273152 times.
✗ Branch 5 not taken.
2273152 if (gtid_state->generate_automatic_gtid(
1681 head,
1682 head->get_transaction()->get_rpl_transaction_ctx()->get_sidno(),
1683 head->get_transaction()->get_rpl_transaction_ctx()->get_gno(),
1684
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2273151 times.
2273152 &locked_sidno) != RETURN_STATUS_OK) {
1685 1 head->commit_error = THD::CE_FLUSH_GNO_EXHAUSTED_ERROR;
1686 1 error = true;
1687 }
1688 } else {
1689
3/8
✓ Branch 0 taken 312172 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 312172 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 312172 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
312172 DBUG_PRINT("info",
1690 ("thd->variables.gtid_next.type=%d "
1691 "thd->owned_gtid.sidno=%d",
1692 head->variables.gtid_next.type, head->owned_gtid.sidno));
1693
2/2
✓ Branch 0 taken 87194 times.
✓ Branch 1 taken 224978 times.
312172 if (head->variables.gtid_next.type == ASSIGNED_GTID)
1694
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87194 times.
87194 assert(head->owned_gtid.sidno > 0);
1695 else {
1696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 224978 times.
224978 assert(head->variables.gtid_next.type == ANONYMOUS_GTID);
1697
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 224978 times.
224978 assert(head->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS);
1698 }
1699 }
1700 }
1701
1702
3/4
✓ Branch 0 taken 36717 times.
✓ Branch 1 taken 2457902 times.
✓ Branch 2 taken 36717 times.
✗ Branch 3 not taken.
2494619 if (locked_sidno > 0) gtid_state->unlock_sidno(locked_sidno);
1703
1704
3/4
✓ Branch 0 taken 2202278 times.
✓ Branch 1 taken 292341 times.
✓ Branch 2 taken 2202278 times.
✗ Branch 3 not taken.
2494619 if (is_global_sid_locked) global_sid_lock->unlock();
1705
1706 2494619 return error;
1707 2494619 }
1708
1709 /**
1710 Write the Gtid_log_event to the binary log (prior to writing the
1711 statement or transaction cache).
1712
1713 @param thd Thread that is committing.
1714 @param cache_data The cache that is flushing.
1715 @param writer The event will be written to this Binlog_event_writer object.
1716
1717 @retval false Success.
1718 @retval true Error.
1719 */
1720 2590142 bool MYSQL_BIN_LOG::write_transaction(THD *thd, binlog_cache_data *cache_data,
1721 Binlog_event_writer *writer) {
1722
1/2
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
2590142 DBUG_TRACE;
1723
1724 /*
1725 The GTID for the THD was assigned at
1726 assign_automatic_gtids_to_flush_group()
1727 */
1728
3/4
✓ Branch 0 taken 123932 times.
✓ Branch 1 taken 2466210 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123932 times.
2590142 assert(thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS ||
1729 thd->owned_gtid.sidno > 0);
1730
1731 int64 sequence_number, last_committed;
1732 /* Generate logical timestamps for MTS */
1733
1/2
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
2590142 m_dependency_tracker.get_dependency(thd, sequence_number, last_committed);
1734
1735 /*
1736 In case both the transaction cache and the statement cache are
1737 non-empty, both will be flushed in sequence and logged as
1738 different transactions. Then the second transaction must only
1739 be executed after the first one has committed. Therefore, we
1740 need to set last_committed for the second transaction equal to
1741 last_committed for the first transaction. This is done in
1742 binlog_cache_data::flush. binlog_cache_data::flush uses the
1743 condition trn_ctx->last_committed==SEQ_UNINIT to detect this
1744 situation, hence the need to set it here.
1745 */
1746 2590142 thd->get_transaction()->last_committed = SEQ_UNINIT;
1747
1748 /*
1749 For delayed replication and also for the purpose of lag monitoring,
1750 we assume that the commit timestamp of the transaction is the time of
1751 executing this code (the time of writing the Gtid_log_event to the binary
1752 log).
1753 */
1754 2590142 ulonglong immediate_commit_timestamp = my_micro_time();
1755
1756 /*
1757 When the original_commit_timestamp session variable is set to a value
1758 other than UNDEFINED_COMMIT_TIMESTAMP, it means that either the timestamp
1759 is known ( > 0 ) or the timestamp is not known ( == 0 ).
1760 */
1761 2590142 ulonglong original_commit_timestamp =
1762 thd->variables.original_commit_timestamp;
1763 /*
1764 When original_commit_timestamp == UNDEFINED_COMMIT_TIMESTAMP, we assume
1765 that:
1766 a) it is not known if this thread is a slave applier ( = 0 );
1767 b) this is a new transaction ( = immediate_commit_timestamp);
1768 */
1769
2/2
✓ Branch 0 taken 2297593 times.
✓ Branch 1 taken 292549 times.
2590142 if (original_commit_timestamp == UNDEFINED_COMMIT_TIMESTAMP) {
1770 /*
1771 When applying a transaction using replication, assume that the
1772 original commit timestamp is not known (the transaction wasn't
1773 originated on the current server).
1774 */
1775
6/6
✓ Branch 0 taken 2297467 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 2297421 times.
✓ Branch 4 taken 172 times.
✓ Branch 5 taken 2297421 times.
2297593 if (thd->slave_thread || thd->is_binlog_applier()) {
1776 172 original_commit_timestamp = 0;
1777 } else
1778 /* Assume that this transaction is original from this server */
1779 {
1780
2/4
✓ Branch 0 taken 2297421 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2297421 times.
2297421 DBUG_EXECUTE_IF("rpl_invalid_gtid_timestamp",
1781 // add one our to the commit timestamps
1782 immediate_commit_timestamp += 3600000000;);
1783 2297421 original_commit_timestamp = immediate_commit_timestamp;
1784 }
1785 } else {
1786 // Clear the session variable to have cleared states for next transaction.
1787 292549 thd->variables.original_commit_timestamp = UNDEFINED_COMMIT_TIMESTAMP;
1788 }
1789
1790 uint32_t trx_immediate_server_version =
1791 2590142 do_server_version_int(::server_version);
1792 // Clear the session variable to have cleared states for next transaction.
1793 2590142 thd->variables.immediate_server_version = UNDEFINED_SERVER_VERSION;
1794
3/4
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2590138 times.
2590142 DBUG_EXECUTE_IF("fixed_server_version",
1795 trx_immediate_server_version = 888888;);
1796
3/4
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2590138 times.
2590142 DBUG_EXECUTE_IF("gr_fixed_server_version",
1797 trx_immediate_server_version = 777777;);
1798
1799 /*
1800 When the original_server_version session variable is set to a value
1801 other than UNDEFINED_SERVER_VERSION, it means that either the
1802 server version is known or the server_version is not known
1803 (UNKNOWN_SERVER_VERSION).
1804 */
1805 2590142 uint32_t trx_original_server_version = thd->variables.original_server_version;
1806
1807 /*
1808 When original_server_version == UNDEFINED_SERVER_VERSION, we assume
1809 that:
1810 a) it is not known if this thread is a slave applier ( = 0 );
1811 b) this is a new transaction ( = ::server_version);
1812 */
1813
2/2
✓ Branch 0 taken 2297613 times.
✓ Branch 1 taken 292529 times.
2590142 if (trx_original_server_version == UNDEFINED_SERVER_VERSION) {
1814 /*
1815 When applying a transaction using replication, assume that the
1816 original server version is not known (the transaction wasn't
1817 originated on the current server).
1818 */
1819
6/6
✓ Branch 0 taken 2297461 times.
✓ Branch 1 taken 152 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 2297421 times.
✓ Branch 4 taken 192 times.
✓ Branch 5 taken 2297421 times.
2297613 if (thd->slave_thread || thd->is_binlog_applier()) {
1820 192 trx_original_server_version = UNKNOWN_SERVER_VERSION;
1821 } else
1822 /* Assume that this transaction is original from this server */
1823 {
1824 2297421 trx_original_server_version = trx_immediate_server_version;
1825 }
1826 } else {
1827 // Clear the session variable to have cleared states for next transaction.
1828 292529 thd->variables.original_server_version = UNDEFINED_SERVER_VERSION;
1829 }
1830 Gtid_log_event gtid_event(
1831 2590142 thd, cache_data->is_trx_cache(), last_committed, sequence_number,
1832 2590142 cache_data->may_have_sbr_stmts(), original_commit_timestamp,
1833 immediate_commit_timestamp, trx_original_server_version,
1834
1/2
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
2590142 trx_immediate_server_version);
1835
1836 // Set the transaction length, based on cache info
1837
2/4
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590142 times.
✗ Branch 3 not taken.
2590142 gtid_event.set_trx_length_by_cache_size(cache_data->get_byte_position(),
1838 2590142 writer->is_checksum_enabled(),
1839 2590142 cache_data->get_event_counter());
1840
1841
6/10
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 2590031 times.
✓ Branch 6 taken 111 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 111 times.
✗ Branch 9 not taken.
2590142 DBUG_PRINT("debug", ("cache_data->get_byte_position()= %llu",
1842 cache_data->get_byte_position()));
1843
5/8
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 2590031 times.
✓ Branch 6 taken 111 times.
✗ Branch 7 not taken.
2590142 DBUG_PRINT("debug", ("cache_data->get_event_counter()= %lu",
1844 static_cast<ulong>(cache_data->get_event_counter())));
1845
6/10
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 2590031 times.
✓ Branch 6 taken 111 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 111 times.
✗ Branch 9 not taken.
2590142 DBUG_PRINT("debug", ("writer->is_checksum_enabled()= %s",
1846 YESNO(writer->is_checksum_enabled())));
1847
6/10
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 2590031 times.
✓ Branch 6 taken 111 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 111 times.
✗ Branch 9 not taken.
2590142 DBUG_PRINT("debug", ("gtid_event.get_event_length()= %lu",
1848 static_cast<ulong>(gtid_event.get_event_length())));
1849
5/8
✓ Branch 0 taken 2590142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 114 times.
✓ Branch 5 taken 2590028 times.
✓ Branch 6 taken 114 times.
✗ Branch 7 not taken.
2590142 DBUG_PRINT("info",
1850 ("transaction_length= %llu", gtid_event.transaction_length));
1851
1852 #ifdef WITH_WSREP
1853 2590142 bool ret = 0;
1854
1855
2/2
✓ Branch 0 taken 2590135 times.
✓ Branch 1 taken 7 times.
2590142 if (!(thd->variables.option_bits & OPTION_BIN_LOG_INTERNAL_OFF) &&
1856
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 2590010 times.
2590135 !(thd->variables.option_bits & OPTION_BIN_LOG))
1857 125 goto end;
1858
1859
1/2
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
2590017 ret = gtid_event.write(writer);
1860 #else
1861 bool ret = gtid_event.write(writer);
1862 #endif
1863
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2590017 times.
2590017 if (ret) goto end;
1864
1865 /*
1866 finally write the transaction data, if it was not compressed
1867 and written as part of the gtid event already
1868 */
1869
1/2
✓ Branch 0 taken 2590014 times.
✗ Branch 1 not taken.
2590017 ret = mysql_bin_log.write_cache(thd, cache_data, writer);
1870
1871
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2590011 times.
2590014 if (!ret) {
1872 // update stats if monitoring is active
1873
1/2
✓ Branch 0 taken 2590011 times.
✗ Branch 1 not taken.
2590011 binlog::global_context.monitoring_context()
1874
1/2
✓ Branch 0 taken 2590011 times.
✗ Branch 1 not taken.
2590011 .transaction_compression()
1875
1/2
✓ Branch 0 taken 2590011 times.
✗ Branch 1 not taken.
5180022 .update(binlog::monitoring::log_type::BINARY,
1876 2590011 cache_data->get_compression_type(), thd->owned_gtid,
1877 2590011 gtid_event.immediate_commit_timestamp,
1878 cache_data->get_compressed_size(),
1879 cache_data->get_decompressed_size());
1880 }
1881
1882 3 end:
1883 2590139 return ret;
1884 2590139 }
1885
1886 1675328 int MYSQL_BIN_LOG::gtid_end_transaction(THD *thd) {
1887
1/2
✓ Branch 0 taken 1676270 times.
✗ Branch 1 not taken.
1675328 DBUG_TRACE;
1888
1889
5/10
✓ Branch 0 taken 1676211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1676264 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 91 times.
✓ Branch 5 taken 1676173 times.
✓ Branch 6 taken 91 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1676270 DBUG_PRINT("info", ("query=%s", thd->query().str));
1890
1891
2/2
✓ Branch 0 taken 50506 times.
✓ Branch 1 taken 1624935 times.
1675441 if (thd->owned_gtid.sidno > 0) {
1892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50506 times.
50506 assert(thd->variables.gtid_next.type == ASSIGNED_GTID);
1893
1894
5/6
✓ Branch 0 taken 50484 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 20156 times.
✓ Branch 3 taken 30328 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20156 times.
50506 if (!opt_bin_log || (thd->slave_thread && !opt_log_replica_updates)) {
1895 /*
1896 If the binary log is disabled for this thread (either by
1897 log_bin=0 or sql_log_bin=0 or by log_replica_updates=0 for a
1898 slave thread), then the statement must not be written to the
1899 binary log. In this case, we just save the GTID into the
1900 table directly.
1901
1902 (This only happens for DDL, since DML will save the GTID into
1903 table and release ownership inside ha_commit_trans.)
1904 */
1905
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (gtid_state->save(thd) != 0) {
1906 gtid_state->update_on_rollback(thd);
1907 return 1;
1908
3/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 17 times.
22 } else if (!has_commit_order_manager(thd)) {
1909 /*
1910 The gtid_state->save implicitly performs the commit, in the following
1911 stack:
1912 Gtid_state::save ->
1913 Gtid_table_persistor::save ->
1914 Gtid_table_access_context::deinit ->
1915 System_table_access::close_table ->
1916 ha_commit_trans ->
1917 Relay_log_info::pre_commit ->
1918 Slave_worker::commit_positions(THD*) ->
1919 Slave_worker::commit_positions(THD*,Log_event*,...) ->
1920 Slave_worker::flush_info ->
1921 Rpl_info_handler::flush_info ->
1922 Rpl_info_table::do_flush_info ->
1923 Rpl_info_table_access::close_table ->
1924 System_table_access::close_table ->
1925 ha_commit_trans ->
1926 MYSQL_BIN_LOG::commit ->
1927 ha_commit_low
1928
1929 If replica-preserve-commit-order is disabled, it does not call
1930 update_on_commit from this stack. The reason is as follows:
1931
1932 In the normal case of MYSQL_BIN_LOG::commit, where the transaction is
1933 going to be written to the binary log, it invokes
1934 MYSQL_BIN_LOG::ordered_commit, which updates the GTID state (the call
1935 gtid_state->update_commit_group(first) in process_commit_stage_queue).
1936 However, when MYSQL_BIN_LOG::commit is invoked from this stack, it is
1937 because the transaction is not going to be written to the binary log,
1938 and then MYSQL_BIN_LOG::commit has a special case that calls
1939 ha_commit_low directly, skipping ordered_commit. Therefore, the GTID
1940 state is not updated in this stack.
1941
1942 On the other hand, if replica-preserve-commit-order is enabled, the
1943 logic that orders commit carries out a subset of the binlog group
1944 commit from within ha_commit_low, and this includes updating the GTID
1945 state. In particular, there is the following call stack under
1946 ha_commit_low:
1947
1948 ha_commit_low ->
1949 Commit_order_manager::wait_and_finish ->
1950 Commit_order_manager::finish ->
1951 Commit_order_manager::flush_engine_and_signal_threads ->
1952 Gtid_state::update_commit_group
1953
1954 Therefore, it is necessary to call update_on_commit only in case we
1955 are not using replica-preserve-commit-order here.
1956 */
1957
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 gtid_state->update_on_commit(thd);
1958 }
1959 } else {
1960 /*
1961 If statement is supposed to be written to binlog, we write it
1962 to the binary log. Inserting into table and releasing
1963 ownership will be done in the binlog commit handler.
1964 */
1965
1966 /*
1967 thd->cache_mngr may be uninitialized if the first transaction
1968 executed by the client is empty.
1969 */
1970
2/4
✓ Branch 0 taken 50484 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50484 times.
50486 if (thd->binlog_setup_trx_data()) return 1;
1971
1/2
✓ Branch 0 taken 50484 times.
✗ Branch 1 not taken.
50484 binlog_cache_data *cache_data = &thd_get_cache_mngr(thd)->trx_cache;
1972
1973 // Generate BEGIN event
1974 Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), true, false, true, 0,
1975
1/2
✓ Branch 0 taken 50484 times.
✗ Branch 1 not taken.
50484 true);
1976
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50484 times.
50484 assert(!qinfo.is_using_immediate_logging());
1977
1978 #ifdef WITH_WSREP
1979
6/8
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 50462 times.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
50484 if (WSREP_ON && thd->slave_thread && !thd->wsrep_applier) {
1980 /* If the galera node is acting as async slave then capture
1981 GTID event from the async slave applied thread and mark it for
1982 replication in galera channel. */
1983 11 thd->wsrep_replicate_GTID = true;
1984
1985 /* Replicating DDL (from async-master) with replication filter will
1986 cause DDL to get skipped way-early before the MySQL flow starts
1987 transaction. Even though there is nothing to commit Galera/PXC flow
1988 needs to capture empty event with GTID and replicate it. For this
1989 it needs an active transaction. Start a transaction in Galera/PXC
1990 context that will be committed as part of binlog_commit action
1991 called below. */
1992
3/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 8 times.
11 if (!wsrep_is_active(thd)) {
1993
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 wsrep_start_transaction(thd, thd->wsrep_next_trx_id());
1994 }
1995 }
1996 #endif /* WITH_WSREP */
1997 /*
1998 Write BEGIN event and then commit (which will generate commit
1999 event and Gtid_log_event)
2000 */
2001
3/8
✓ Branch 0 taken 50484 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50484 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 50484 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
50484 DBUG_PRINT("debug", ("Writing to trx_cache"));
2002
7/10
✓ Branch 0 taken 50484 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50484 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 50484 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 50482 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 50482 times.
50484 if (cache_data->write_event(&qinfo) || mysql_bin_log.commit(thd, true))
2003 2 return 1;
2004
2005 #ifdef WITH_WSREP
2006 50482 thd->wsrep_replicate_GTID = false;
2007 #endif /* WITH_WSREP */
2008
2/2
✓ Branch 0 taken 50482 times.
✓ Branch 1 taken 2 times.
50484 }
2009
2/2
✓ Branch 0 taken 1558282 times.
✓ Branch 1 taken 66653 times.
1624935 } else if (thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS ||
2010 /*
2011 A transaction with an empty owned gtid should call
2012 end_gtid_violating_transaction(...) to clear the
2013 flag thd->has_gtid_consistency_violatoin in case
2014 it is set. It missed the clear in ordered_commit,
2015 because its binlog transaction cache is empty.
2016 */
2017
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1558432 times.
1558282 thd->has_gtid_consistency_violation)
2018
2019 {
2020
1/2
✓ Branch 0 taken 66626 times.
✗ Branch 1 not taken.
66503 gtid_state->update_on_commit(thd);
2021 #ifdef WITH_WSREP
2022 /* if setup is operating with gtid_mode=OFF + replication filter
2023 then replication of DML event can cause start of transaction (as part of
2024 BEGIN event) but the followup action of apply is blocked or skipped
2025 by presence of replication filter.
2026 binlog-commit will commit the transaction in InnoDB world but
2027 PXC needs to be ensure the said transaction is closed as empty
2028 transaction (just like SELECT empty transaction). */
2029
3/4
✓ Branch 0 taken 66625 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 66611 times.
66626 if (wsrep_is_active(thd)) {
2030
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
14 wsrep_commit_empty(thd, true);
2031 }
2032 #endif /* WITH_WSREP */
2033
4/4
✓ Branch 0 taken 12694 times.
✓ Branch 1 taken 1545738 times.
✓ Branch 2 taken 12696 times.
✓ Branch 3 taken 1545737 times.
1571127 } else if (thd->variables.gtid_next.type == ASSIGNED_GTID &&
2034
2/4
✓ Branch 0 taken 12695 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12696 times.
✗ Branch 3 not taken.
12694 thd->owned_gtid_is_empty()) {
2035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12696 times.
12696 assert(thd->has_gtid_consistency_violation == false);
2036
1/2
✓ Branch 0 taken 12693 times.
✗ Branch 1 not taken.
12696 gtid_state->update_on_commit(thd);
2037 }
2038
2039 1675564 return 0;
2040 1675566 }
2041
2042 77 bool MYSQL_BIN_LOG::reencrypt_logs() {
2043
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 DBUG_TRACE;
2044
2045
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 if (!is_open()) return false;
2046
2047 77 std::string error_message;
2048 /* Gather the set of files to be accessed. */
2049 77 list<string> filename_list;
2050 77 LOG_INFO linfo;
2051 77 int error = 0;
2052 77 list<string>::reverse_iterator rit;
2053
2054 /* Read binary/relay log file names from index file. */
2055
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 mysql_mutex_lock(&LOCK_index);
2056
3/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1357 times.
✓ Branch 3 taken 77 times.
1434 for (error = find_log_pos(&linfo, nullptr, false); !error;
2057 1357 error = find_next_log(&linfo, false)) {
2058
3/6
✓ Branch 0 taken 1357 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1357 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1357 times.
✗ Branch 5 not taken.
1357 filename_list.push_back(string(linfo.log_file_name));
2059 }
2060
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 mysql_mutex_unlock(&LOCK_index);
2061
3/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 75 times.
154 if (error != LOG_INFO_EOF ||
2062
3/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 75 times.
77 DBUG_EVALUATE_IF("fail_to_open_index_file", true, false)) {
2063
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.assign("I/O error reading index file '");
2064
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.append(index_file_name);
2065
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.append("'");
2066 2 goto err;
2067 }
2068
2069 75 rit = filename_list.rbegin();
2070 /* Skip the last binary/relay log. */
2071
3/6
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
75 if (rit != filename_list.rend()) rit++;
2072 /* Iterate backwards through binary/relay logs. */
2073
3/4
✓ Branch 0 taken 1226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1162 times.
✓ Branch 3 taken 64 times.
1226 while (rit != filename_list.rend()) {
2074
1/2
✓ Branch 0 taken 1162 times.
✗ Branch 1 not taken.
1162 const char *filename = rit->c_str();
2075
4/6
✓ Branch 0 taken 1162 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1161 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1162 DBUG_EXECUTE_IF("purge_logs_during_reencryption", {
2076 purge_logs(filename, true, true /*need_lock_index=true*/,
2077 true /*need_update_threads=true*/, nullptr, false);
2078 });
2079 1162 MUTEX_LOCK(lock, &LOCK_index);
2080 std::unique_ptr<Binlog_ofile> ofile(
2081
1/2
✓ Branch 0 taken 1162 times.
✗ Branch 1 not taken.
1162 Binlog_ofile::open_existing(key_file_binlog, filename, MYF(MY_WME)));
2082
2083 1162 if (ofile == nullptr ||
2084
7/8
✓ Branch 0 taken 1161 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1161 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1159 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 1158 times.
2321 DBUG_EVALUATE_IF("fail_to_open_log_file", true, false) ||
2085
3/4
✓ Branch 0 taken 1159 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1158 times.
1159 DBUG_EVALUATE_IF("fail_to_read_index_file", true, false)) {
2086 /* If we can not open the log file, check if it exists in index file. */
2087
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 error = find_log_pos(&linfo, filename, false);
2088
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
4 DBUG_EXECUTE_IF("fail_to_read_index_file", error = LOG_INFO_IO;);
2089
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (error == LOG_INFO_EOF) {
2090 /* If it does not exist in index file, re-encryption has finished. */
2091
5/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 if (current_thd->is_error()) current_thd->clear_error();
2092 1 break;
2093
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 } else if (error == 0) {
2094 /* If it exists in index file, failed to open the log file. */
2095
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.assign("Failed to open log file '");
2096
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.append(filename);
2097
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.append("'");
2098 2 goto err;
2099
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (error == LOG_INFO_IO) {
2100 /* Failed to read index file. */
2101
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 error_message.assign("I/O error reading index file '");
2102
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 error_message.append(index_file_name);
2103
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 error_message.append("'");
2104 1 goto err;
2105 }
2106 }
2107
2108
2/2
✓ Branch 0 taken 1070 times.
✓ Branch 1 taken 88 times.
1158 if (ofile->is_encrypted()) {
2109 std::unique_ptr<Truncatable_ostream> pipeline_head =
2110 1070 ofile->get_pipeline_head();
2111 std::unique_ptr<Binlog_encryption_ostream> binlog_encryption_ostream(
2112 1070 down_cast<Binlog_encryption_ostream *>(pipeline_head.release()));
2113
2114
1/2
✓ Branch 0 taken 1070 times.
✗ Branch 1 not taken.
1070 auto ret_value = binlog_encryption_ostream->reencrypt();
2115
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1063 times.
1070 if (ret_value.first) {
2116
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error_message.assign("Failed to re-encrypt log file '");
2117
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error_message.append(filename);
2118
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error_message.append("': ");
2119
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error_message.append(ret_value.second.c_str());
2120 7 goto err;
2121 }
2122
6/6
✓ Branch 0 taken 1063 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1063 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1063 times.
✓ Branch 5 taken 7 times.
1084 }
2123
2124
1/2
✓ Branch 0 taken 1151 times.
✗ Branch 1 not taken.
1151 rit++;
2125
6/6
✓ Branch 0 taken 1151 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 1151 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 10 times.
1173 }
2126
2127 65 filename_list.clear();
2128
2129 65 return false;
2130
2131 12 err:
2132
3/10
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
12 if (current_thd->is_error()) current_thd->clear_error();
2133
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 my_error(ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_REENCRYPT_LOG, MYF(0),
2134 error_message.c_str());
2135 12 filename_list.clear();
2136
2137 12 return true;
2138 77 }
2139
2140 2590897 bool binlog_cache_data::compress(THD *thd) {
2141
1/2
✓ Branch 0 taken 2591159 times.
✗ Branch 1 not taken.
2590897 DBUG_TRACE;
2142 2591159 auto error{false};
2143 2591159 auto ctype{binary_log::transaction::compression::type::NONE};
2144
1/2
✓ Branch 0 taken 2591137 times.
✗ Branch 1 not taken.
2591159 auto uncompressed_size{m_cache.length()};
2145 2591137 auto size{uncompressed_size};
2146 2591137 auto &cctx{thd->rpl_thd_ctx.transaction_compression_ctx()};
2147 2591001 binary_log::transaction::compression::Compressor *compressor{nullptr};
2148
2149 // no compression enabled (ctype == NONE at this point)
2150
2/2
✓ Branch 0 taken 2590914 times.
✓ Branch 1 taken 87 times.
2591001 if (thd->variables.binlog_trx_compression == false) goto end;
2151
2152 // do not compress if there are incident events
2153
3/4
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 163 times.
87 DBUG_EXECUTE_IF("binlog_compression_inject_incident", set_incident(););
2154
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 163 times.
165 if (has_incident()) goto end;
2155
2156 // do not compress if there are non-transactional changes
2157 163 if (thd->get_transaction()->has_modified_non_trans_table(
2158
6/6
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 155 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 155 times.
319 Transaction_ctx::STMT) ||
2159 156 thd->get_transaction()->has_modified_non_trans_table(
2160 Transaction_ctx::SESSION))
2161 8 goto end;
2162
2163 // do not compress if has SBR
2164
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 60 times.
155 if (may_have_sbr_stmts()) goto end;
2165
2166 // Unable to get a reference to a compressor, fallback to
2167 // non compressed
2168
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
60 if ((compressor = cctx.get_compressor(thd)) == nullptr) goto end;
2169
2170 // compression is enabled and all pre-conditions checked.
2171 // now compress
2172 else {
2173 60 std::size_t old_capacity{0};
2174 60 unsigned char *buffer{nullptr};
2175 60 unsigned char *old_buffer{nullptr};
2176
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 Transaction_payload_log_event tple{thd};
2177
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 Compressed_ostream stream;
2178 60 PSI_stage_info old_stage;
2179
2180 // set the thread stage to compressing transaction
2181
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 thd->enter_stage(&stage_binlog_transaction_compress, &old_stage, __func__,
2182 __FILE__, __LINE__);
2183 // do we have enough compression buffer ? If not swap with a larger one
2184
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
60 std::tie(buffer, std::ignore, old_capacity) = compressor->get_buffer();
2185
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 28 times.
60 if (old_capacity < size) {
2186 32 old_buffer = buffer;
2187 32 auto new_buffer = (unsigned char *)malloc(size);
2188
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 if (new_buffer)
2189
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 compressor->set_buffer(new_buffer, size);
2190 else {
2191 /* purecov: begin inspected */
2192 // OOM
2193 error = true;
2194 goto compression_end;
2195 /* purecov: end */
2196 }
2197 }
2198
2199
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 ctype = compressor->compression_type_code();
2200
2201
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 compressor->open();
2202
2203 // inject the compressor in the output stream
2204
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 stream.set_compressor(compressor);
2205
2206 // FIXME: innefficient, we should not copy caches around
2207 // This should be fixed when we revamp the capture
2208 // cache handling (and make this more geared towards
2209 // possible enhancements, such as streaming the changes)
2210 // Also, if the cache actually spills to disk, this may
2211 // the impact may be amplified, since reiniting the
2212 // causes a flush to disk
2213
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
60 if ((error = m_cache.copy_to(&stream))) goto compression_end;
2214
2215
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 compressor->close();
2216
2217
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
60 if ((error = m_cache.truncate(0))) goto compression_end;
2218 // Since we deleted all events from the cache, we also need to
2219 // reset event_counter.
2220 60 event_counter = 0;
2221
2222 // fill in the new transport event
2223
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
60 std::tie(buffer, size, std::ignore) = compressor->get_buffer();
2224 60 tple.set_payload((const char *)buffer);
2225 60 tple.set_payload_size(size);
2226 60 tple.set_compression_type(ctype);
2227 60 tple.set_uncompressed_size(uncompressed_size);
2228
2229 // write back the new cache contents
2230
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 error = write_event(&tple);
2231
2232 60 compression_end:
2233 // revert back to the default buffer, so that we don't overuse memory
2234
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 28 times.
60 if (old_buffer) {
2235
2/4
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
32 std::tie(buffer, std::ignore, std::ignore) = compressor->get_buffer();
2236
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 compressor->set_buffer(old_buffer, old_capacity);
2237 32 free(buffer);
2238 }
2239
2240 // revert the stage if needed
2241
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
60 if (old_stage.m_key != 0) THD_STAGE_INFO(thd, old_stage);
2242 60 }
2243
2244 2591079 end:
2245
2/2
✓ Branch 0 taken 2590897 times.
✓ Branch 1 taken 182 times.
2591079 if (!error) {
2246 2590897 set_compression_type(ctype);
2247
1/2
✓ Branch 0 taken 2591053 times.
✗ Branch 1 not taken.
2590970 set_compressed_size(m_cache.length());
2248 2591041 set_decompressed_size(uncompressed_size);
2249 }
2250 2591189 return error;
2251 2591233 }
2252
2253 /**
2254 This function finalizes the cache preparing for commit or rollback.
2255
2256 The function just writes all the necessary events to the cache but
2257 does not flush the data to the binary log file. That is the role of
2258 the binlog_cache_data::flush function.
2259
2260 @see binlog_cache_data::flush
2261
2262 @param thd The thread whose transaction should be flushed
2263 @param end_event The end event either commit/rollback
2264
2265 @return
2266 nonzero if an error pops up when flushing the cache.
2267 */
2268 2590839 int binlog_cache_data::finalize(THD *thd, Log_event *end_event) {
2269
1/2
✓ Branch 0 taken 2591171 times.
✗ Branch 1 not taken.
2590839 DBUG_TRACE;
2270
2/4
✓ Branch 0 taken 2591177 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2591181 times.
✗ Branch 3 not taken.
2591171 if (!is_binlog_empty()) {
2271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2591181 times.
2591181 assert(!flags.finalized);
2272
2/4
✓ Branch 0 taken 2590891 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2590891 times.
2591181 if (int error = flush_pending_event(thd)) return error;
2273
2/4
✓ Branch 0 taken 2591191 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2591191 times.
2590891 if (int error = write_event(end_event)) return error;
2274
2/4
✓ Branch 0 taken 2591143 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2591143 times.
2591191 if (int error = this->compress(thd)) return error;
2275
6/10
✓ Branch 0 taken 2591123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2591152 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 2591041 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 111 times.
✓ Branch 8 taken 115 times.
✗ Branch 9 not taken.
2591143 DBUG_PRINT("debug", ("flags.finalized: %s", YESNO(flags.finalized)));
2276 2591156 flags.finalized = true;
2277 }
2278 2591152 return 0;
2279 2591152 }
2280
2281 /**
2282 The method writes XA END query to XA-prepared transaction's cache
2283 and calls the "basic" finalize().
2284
2285 @return error code, 0 success
2286 */
2287
2288 638 int binlog_cache_data::finalize(THD *thd, Log_event *end_event, XID_STATE *xs) {
2289 638 int error = 0;
2290 char buf[XID::ser_buf_size];
2291 char query[sizeof("XA END") + 1 + sizeof(buf)];
2292 638 int qlen = sprintf(query, "XA END %s", xs->get_xid()->serialize(buf));
2293
1/2
✓ Branch 0 taken 638 times.
✗ Branch 1 not taken.
638 Query_log_event qev(thd, query, qlen, true, false, true, 0);
2294
2295
2/4
✓ Branch 0 taken 638 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 638 times.
638 if ((error = write_event(&qev))) return error;
2296
2297
1/2
✓ Branch 0 taken 638 times.
✗ Branch 1 not taken.
638 return finalize(thd, end_event);
2298 638 }
2299
2300 /**
2301 Flush caches to the binary log.
2302
2303 If the cache is finalized, the cache will be flushed to the binary
2304 log file. If the cache is not finalized, nothing will be done.
2305
2306 If flushing fails for any reason, an error will be reported and the
2307 cache will be reset. Flushing can fail in two circumstances:
2308
2309 - It was not possible to write the cache to the file. In this case,
2310 it does not make sense to keep the cache.
2311
2312 - The cache was successfully written to disk but post-flush actions
2313 (such as binary log rotation) failed. In this case, the cache is
2314 already written to disk and there is no reason to keep it.
2315
2316 @see binlog_cache_data::finalize
2317 */
2318 5170646 int binlog_cache_data::flush(THD *thd, my_off_t *bytes_written,
2319 bool *wrote_xid) {
2320 /*
2321 Doing a commit or a rollback including non-transactional tables,
2322 i.e., ending a transaction where we might write the transaction
2323 cache to the binary log.
2324
2325 We can always end the statement when ending a transaction since
2326 transactions are not allowed inside stored functions. If they
2327 were, we would have to ensure that we're not ending a statement
2328 inside a stored function.
2329 */
2330
1/2
✓ Branch 0 taken 5170646 times.
✗ Branch 1 not taken.
5170646 DBUG_TRACE;
2331
7/10
✓ Branch 0 taken 5170646 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5170646 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 221 times.
✓ Branch 5 taken 5170425 times.
✓ Branch 6 taken 111 times.
✓ Branch 7 taken 110 times.
✓ Branch 8 taken 221 times.
✗ Branch 9 not taken.
5170646 DBUG_PRINT("debug", ("flags.finalized: %s", YESNO(flags.finalized)));
2332 5170646 int error = 0;
2333
2/2
✓ Branch 0 taken 2590143 times.
✓ Branch 1 taken 2580503 times.
5170646 if (flags.finalized) {
2334
1/2
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
2590143 my_off_t bytes_in_cache = m_cache.length();
2335 2590143 Transaction_ctx *trn_ctx = thd->get_transaction();
2336
2337
5/8
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590143 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 2590032 times.
✓ Branch 6 taken 111 times.
✗ Branch 7 not taken.
2590143 DBUG_PRINT("debug", ("bytes_in_cache: %llu", bytes_in_cache));
2338
2339
1/2
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
2590143 trn_ctx->sequence_number = mysql_bin_log.m_dependency_tracker.step();
2340
2341 /*
2342 In case of two caches the transaction is split into two groups.
2343 The 2nd group is considered to be a successor of the 1st rather
2344 than to have a common commit parent with it.
2345 Notice that due to a simple method of detection that the current is
2346 the 2nd cache being flushed, the very first few transactions may be logged
2347 sequentially (a next one is tagged as if a preceding one is its
2348 commit parent).
2349 */
2350
2/2
✓ Branch 0 taken 71022 times.
✓ Branch 1 taken 2519121 times.
2590143 if (trn_ctx->last_committed == SEQ_UNINIT)
2351 71022 trn_ctx->last_committed = trn_ctx->sequence_number - 1;
2352
2353 /*
2354 The GTID is written prior to flushing the statement cache, if
2355 the transaction has written to the statement cache; and prior to
2356 flushing the transaction cache if the transaction has written to
2357 the transaction cache. If GTIDs are enabled, then transactional
2358 and non-transactional updates cannot be mixed, so at most one of
2359 the caches can be non-empty, so just one GTID will be
2360 generated. If GTIDs are disabled, then no GTID is generated at
2361 all; if both the transactional cache and the statement cache are
2362 non-empty then we get two Anonymous_gtid_log_events, which is
2363 correct.
2364 */
2365
1/2
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
2590143 Binlog_event_writer writer(mysql_bin_log.get_binlog_file(), thd);
2366
2367 /* The GTID ownership process might set the commit_error */
2368
1/2
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
5180286 error = (thd->commit_error == THD::CE_FLUSH_ERROR ||
2369
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2590142 times.
2590143 thd->commit_error == THD::CE_FLUSH_GNO_EXHAUSTED_ERROR);
2370
2371
5/6
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29940 times.
✓ Branch 3 taken 2560203 times.
✓ Branch 4 taken 9946 times.
✓ Branch 5 taken 19994 times.
2590143 DBUG_EXECUTE_IF("simulate_binlog_flush_error", {
2372 if (rand() % 3 == 0) {
2373 thd->commit_error = THD::CE_FLUSH_ERROR;
2374 }
2375 };);
2376
2377
4/6
✓ Branch 0 taken 2590143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2590142 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2590143 DBUG_EXECUTE_IF("fault_injection_reinit_io_cache_while_flushing_to_file",
2378 { DBUG_SET("+d,fault_injection_reinit_io_cache"); });
2379
2380
2/2
✓ Branch 0 taken 2590142 times.
✓ Branch 1 taken 1 times.
2590143 if (!error)
2381
3/4
✓ Branch 0 taken 2590139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2590136 times.
2590142 if ((error = mysql_bin_log.write_transaction(thd, this, &writer)))
2382 3 thd->commit_error = THD::CE_FLUSH_ERROR;
2383
2384
4/6
✓ Branch 0 taken 2590140 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2590139 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2590140 DBUG_EXECUTE_IF("fault_injection_reinit_io_cache_while_flushing_to_file",
2385 { DBUG_SET("-d,fault_injection_reinit_io_cache"); });
2386
2387
4/4
✓ Branch 0 taken 2039492 times.
✓ Branch 1 taken 550648 times.
✓ Branch 2 taken 2039489 times.
✓ Branch 3 taken 3 times.
2590140 if (flags.with_xid && error == 0) *wrote_xid = true;
2388
2389 /*
2390 Reset have to be after the if above, since it clears the
2391 with_xid flag
2392 */
2393
1/2
✓ Branch 0 taken 2590140 times.
✗ Branch 1 not taken.
2590140 reset();
2394
1/2
✓ Branch 0 taken 2590140 times.
✗ Branch 1 not taken.
2590140 if (bytes_written) *bytes_written = bytes_in_cache;
2395 2590140 }
2396
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5170643 times.
5170643 assert(!flags.finalized);
2397 5170643 return error;
2398 5170643 }
2399
2400 /**
2401 This function truncates the transactional cache upon committing or rolling
2402 back either a transaction or a statement.
2403
2404 @param thd The thread whose transaction should be flushed
2405 @param all @c true means truncate the transaction, otherwise the
2406 statement must be truncated.
2407
2408 @return
2409 nonzero if an error pops up when truncating the transactional cache.
2410 */
2411 8941 int binlog_trx_cache_data::truncate(THD *thd, bool all) {
2412
1/2
✓ Branch 0 taken 8951 times.
✗ Branch 1 not taken.
8941 DBUG_TRACE;
2413 8951 int error = 0;
2414
2415
3/14
✓ Branch 0 taken 8951 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8951 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8951 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
8951 DBUG_PRINT("info",
2416 ("thd->options={ %s %s}, transaction: %s",
2417 FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT),
2418 FLAGSTR(thd->variables.option_bits, OPTION_BEGIN),
2419 all ? "all" : "stmt"));
2420
2421
1/2
✓ Branch 0 taken 8945 times.
✗ Branch 1 not taken.
8951 remove_pending_event();
2422
2423 /*
2424 If rolling back an entire transaction or a single statement not
2425 inside a transaction, we reset the transaction cache.
2426 Even though formally the atomic DDL statement may not end multi-statement
2427 transaction the cache needs full resetting as there must
2428 be no other data in it but belonging to the DDL.
2429 */
2430
3/4
✓ Branch 0 taken 8943 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4718 times.
✓ Branch 3 taken 4225 times.
8945 if (ending_trans(thd, all)) {
2431
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4717 times.
4718 if (has_incident()) {
2432 2 const char *err_msg =
2433 "Error happend while resetting the transaction "
2434 "cache for a rolled back transaction or a single "
2435 "statement not inside a transaction.";
2436
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error = mysql_bin_log.write_incident(thd, true /*need_lock_log=true*/,
2437 err_msg);
2438 }
2439
1/2
✓ Branch 0 taken 4719 times.
✗ Branch 1 not taken.
4719 reset();
2440 }
2441 /*
2442 If rolling back a statement in a transaction, we truncate the
2443 transaction cache to remove the statement.
2444 */
2445
2/2
✓ Branch 0 taken 1242 times.
✓ Branch 1 taken 2982 times.
4225 else if (get_prev_position() != MY_OFF_T_UNDEF)
2446
1/2
✓ Branch 0 taken 1242 times.
✗ Branch 1 not taken.
1242 restore_prev_position();
2447
2448 8943 thd->clear_binlog_table_maps();
2449
2450 8950 return error;
2451 8945 }
2452
2453 2101893 inline enum xa_option_words get_xa_opt(THD *thd) {
2454 2101893 enum xa_option_words xa_opt = XA_NONE;
2455
2/2
✓ Branch 0 taken 1188 times.
✓ Branch 1 taken 2100705 times.
2101893 switch (thd->lex->sql_command) {
2456 1188 case SQLCOM_XA_COMMIT:
2457 xa_opt =
2458 1188 static_cast<Sql_cmd_xa_commit *>(thd->lex->m_sql_cmd)->get_xa_opt();
2459 1188 break;
2460 2100705 default:
2461 2100705 break;
2462 }
2463
2464 2101893 return xa_opt;
2465 }
2466
2467 /**
2468 Predicate function yields true when XA transaction is
2469 being logged having a proper state ready for prepare or
2470 commit in one phase.
2471
2472 @param thd THD pointer of running transaction
2473 @return true When the being prepared transaction should be binlogged,
2474 false otherwise.
2475 */
2476
2477 35853195 inline bool is_loggable_xa_prepare(THD *thd) {
2478 /*
2479 simulate_commit_failure is doing a trick with XID_STATE while
2480 the ongoing transaction is not XA, and therefore to be errored out,
2481 asserted below. In that case because of the
2482 latter fact the function returns @c false.
2483 */
2484
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 35853653 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
35853195 DBUG_EXECUTE_IF("simulate_commit_failure", {
2485 XID_STATE *xs = thd->get_transaction()->xid_state();
2486 assert((thd->is_error() && xs->get_state() == XID_STATE::XA_IDLE) ||
2487 xs->get_state() == XID_STATE::XA_NOTR);
2488 });
2489
2490
3/4
✓ Branch 0 taken 35854350 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2477 times.
✓ Branch 3 taken 35852580 times.
35853653 return DBUG_EVALUATE_IF(
2491 "simulate_commit_failure", false,
2492 thd->get_transaction()->xid_state()->has_state(XID_STATE::XA_IDLE));
2493 }
2494
2495 4974099 static int binlog_prepare(handlerton *, THD *thd, bool all) {
2496
1/2
✓ Branch 0 taken 4974180 times.
✗ Branch 1 not taken.
4974099 DBUG_TRACE;
2497
2/2
✓ Branch 0 taken 4437490 times.
✓ Branch 1 taken 536690 times.
4974180 if (!all) {
2498
1/2
✓ Branch 0 taken 4437429 times.
✗ Branch 1 not taken.
4437490 thd->get_transaction()->store_commit_parent(
2499 mysql_bin_log.m_dependency_tracker.get_max_committed_timestamp());
2500 }
2501 4974189 return 0;
2502 4974113 }
2503
2504 530 static int binlog_set_prepared_in_tc(handlerton *, THD *) { return 0; }
2505
2506 /**
2507 Logging XA commit/rollback of a prepared transaction in the case
2508 it was disconnected and resumed (recovered), or executed by a slave applier.
2509
2510 @param thd THD handle
2511 @param xid a pointer to XID object
2512 @param commit when @c true XA-COMMIT is logged, otherwise XA-ROLLBACK
2513
2514 @return error code, 0 success
2515 */
2516 1325 int MYSQL_BIN_LOG::write_xa_to_cache(THD *thd) {
2517
3/4
✓ Branch 0 taken 239 times.
✓ Branch 1 taken 1086 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 239 times.
1325 assert(thd->lex->sql_command == SQLCOM_XA_COMMIT ||
2518 thd->lex->sql_command == SQLCOM_XA_ROLLBACK);
2519
2520
3/4
✓ Branch 0 taken 1325 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 194 times.
✓ Branch 3 taken 1131 times.
1325 if (get_xa_opt(thd) == XA_ONE_PHASE) return 0;
2521
2522 1131 auto xid_state = thd->get_transaction()->xid_state();
2523
2/2
✓ Branch 0 taken 571 times.
✓ Branch 1 taken 560 times.
1131 if (!xid_state->is_binlogged())
2524 571 return 0; // nothing was really logged at prepare
2525
2526
7/10
✓ Branch 0 taken 560 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 558 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 558 times.
560 if (thd->is_error() && DBUG_EVALUATE_IF("simulate_xa_rm_error", 0, 1))
2527 2 return 0; // don't binlog if there are some errors.
2528
2529 558 auto xid_to_write = xid_state->get_xid();
2530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 558 times.
558 assert(xid_to_write != nullptr);
2531
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 558 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
558 assert(!xid_to_write->is_null() ||
2532 !(thd->variables.option_bits & OPTION_BIN_LOG));
2533
2534
1/2
✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
558 std::ostringstream oss;
2535 oss << "XA "
2536 558 << (thd->lex->sql_command == SQLCOM_XA_COMMIT ? "COMMIT" : "ROLLBACK")
2537
7/12
✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 412 times.
✓ Branch 3 taken 146 times.
✓ Branch 4 taken 558 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 558 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 558 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 558 times.
✗ Branch 11 not taken.
558 << " " << *xid_to_write << std::flush;
2538
1/2
✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
558 auto query = oss.str();
2539 558 Query_log_event qinfo(thd, query.data(), query.length(), false, true, true, 0,
2540
1/2
✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
1116 false);
2541
1/2
✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
558 return this->write_event(&qinfo);
2542 558 }
2543
2544 55 static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd) {
2545
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 DBUG_ENTER("binlog_start_consistent_snapshot");
2546
2547 #ifdef WITH_WSREP
2548 /* If operating in emulation binlog mode avoid binlog snapshot as
2549 binlog is not open. */
2550
6/12
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 54 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
55 if (WSREP_EMULATE_BINLOG(thd)) DBUG_RETURN(0);
2551 #endif /* WITH_WSREP */
2552
2553
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 int err = thd->binlog_setup_trx_data();
2554
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
55 if (err) DBUG_RETURN(err);
2555
2556
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
2557
2558 /* Server layer calls us with LOCK_log locked, so this is safe. */
2559
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 mysql_bin_log.raw_get_current_log(&cache_mngr->binlog_info);
2560
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 gtid_state->get_snapshot_gtid_executed(cache_mngr->snapshot_gtid_executed);
2561
2562
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 trans_register_ha(thd, true, hton, nullptr);
2563
2564
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 DBUG_RETURN(err);
2565 }
2566
2567 21 static int binlog_clone_consistent_snapshot(handlerton *hton, THD *thd,
2568 THD *from_thd) {
2569
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 DBUG_ENTER("binlog_start_consistent_snapshot");
2570
2571 #ifdef WITH_WSREP
2572 /* If operating in emulation binlog mode avoid binlog snapshot as
2573 binlog is not open. */
2574
2/12
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
21 if (WSREP_EMULATE_BINLOG(thd)) DBUG_RETURN(0);
2575 #endif /* WITH_WSREP */
2576
2577 const binlog_cache_mngr *from_cache_mngr =
2578 opt_bin_log
2579
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
21 ? static_cast<binlog_cache_mngr *>(thd_get_cache_mngr(from_thd))
2580 21 : nullptr;
2581
2582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (from_cache_mngr == nullptr) {
2583 push_warning_printf(thd, Sql_condition::SL_WARNING, HA_ERR_UNSUPPORTED,
2584 "WITH CONSISTENT SNAPSHOT FROM SESSION was ignored for "
2585 "binary log, because the specified session does not "
2586 "have a consistent snapshot of binary log "
2587 "coordinates.");
2588 DBUG_RETURN(0);
2589 }
2590
2591
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 int err = thd->binlog_setup_trx_data();
2592
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
21 if (err) DBUG_RETURN(err);
2593
2594
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
2595
2596 21 const my_off_t pos = from_cache_mngr->binlog_info.pos;
2597 char log_file_name[FN_REFLEN];
2598
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 strmake(log_file_name, from_cache_mngr->binlog_info.log_file_name,
2599 sizeof(log_file_name) - 1);
2600
2601
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 mysql_mutex_lock(&thd->LOCK_thd_data);
2602
2603
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 cache_mngr->snapshot_gtid_executed = from_cache_mngr->snapshot_gtid_executed;
2604 21 cache_mngr->binlog_info.pos = pos;
2605
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 strmake(cache_mngr->binlog_info.log_file_name, log_file_name,
2606 sizeof(cache_mngr->binlog_info.log_file_name) - 1);
2607
2608
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 mysql_mutex_unlock(&thd->LOCK_thd_data);
2609
2610
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 trans_register_ha(thd, true, hton, nullptr);
2611
2612
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 DBUG_RETURN(err);
2613 }
2614
2615 /**
2616 When a fatal error occurs due to which binary logging becomes impossible and
2617 the user specified binlog_error_action= ABORT_SERVER the following function is
2618 invoked. This function pushes the appropriate error message to client and logs
2619 the same to server error log and then aborts the server.
2620
2621 @param err_string Error string which specifies the exact error
2622 message from the caller.
2623 */
2624 static void exec_binlog_error_action_abort(const char *err_string) {
2625 THD *thd = current_thd;
2626 /*
2627 When the code enters here it means that there was an error at higher layer
2628 and my_error function could have been invoked to let the client know what
2629 went wrong during the execution.
2630
2631 But these errors will not let the client know that the server is going to
2632 abort. Even if we add an additional my_error function call at this point
2633 client will be able to see only the first error message that was set
2634 during the very first invocation of my_error function call.
2635
2636 The advantage of having multiple my_error function calls are visible when
2637 the server is up and running and user issues SHOW WARNINGS or SHOW ERROR
2638 calls. In this special scenario server will be immediately aborted and
2639 user will not be able execute the above SHOW commands.
2640
2641 Hence we clear the previous errors and push one critical error message to
2642 clients.
2643 */
2644 if (thd) {
2645 if (thd->is_error()) thd->clear_error();
2646 /*
2647 Send error to both client and to the server error log.
2648 */
2649 my_error(ER_BINLOG_LOGGING_IMPOSSIBLE, MYF(ME_FATALERROR), err_string);
2650 }
2651
2652 LogErr(ERROR_LEVEL, ER_BINLOG_LOGGING_NOT_POSSIBLE, err_string);
2653 flush_error_log_messages();
2654
2655 if (thd) thd->send_statement_status();
2656 my_abort();
2657 }
2658
2659 /**
2660 This function is called once after each statement.
2661
2662 @todo This function is currently not used any more and will
2663 eventually be eliminated. The real commit job is done in the
2664 MYSQL_BIN_LOG::commit function.
2665
2666 @see MYSQL_BIN_LOG::commit
2667
2668 @see handlerton::commit
2669 */
2670 5461006 static int binlog_commit(handlerton *, THD *, bool) {
2671
1/2
✓ Branch 0 taken 5461106 times.
✗ Branch 1 not taken.
5461006 DBUG_TRACE;
2672 /*
2673 Nothing to do (any more) on commit.
2674 */
2675 5461122 return 0;
2676 5461106 }
2677
2678 /**
2679 This function is called when a transaction or a statement is rolled back.
2680
2681 @internal It is necessary to execute a rollback here if the
2682 transaction was rolled back because of executing a ROLLBACK TO
2683 SAVEPOINT command, but it is not used for normal rollback since
2684 MYSQL_BIN_LOG::rollback is called in that case.
2685
2686 @todo Refactor code to introduce a <code>MYSQL_BIN_LOG::rollback(THD
2687 *thd, SAVEPOINT *sv)</code> function in @c TC_LOG and have that
2688 function execute the necessary work to rollback to a savepoint.
2689
2690 @param thd The client thread that executes the transaction.
2691 @param all This is @c true if this is a real transaction rollback, and
2692 @false otherwise.
2693
2694 @see handlerton::rollback
2695 */
2696 8015 static int binlog_rollback(handlerton *, THD *thd, bool all) {
2697
1/2
✓ Branch 0 taken 8017 times.
✗ Branch 1 not taken.
8015 DBUG_TRACE;
2698 8017 int error = 0;
2699 #ifdef WITH_WSREP
2700
6/6
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 7983 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 7984 times.
8051 if (thd->lex->sql_command == SQLCOM_ROLLBACK_TO_SAVEPOINT &&
2701 34 thd->wsrep_trx().state() != wsrep::transaction::s_aborting)
2702 #else
2703 if (thd->lex->sql_command == SQLCOM_ROLLBACK_TO_SAVEPOINT)
2704 #endif /* WITH_WSREP */
2705
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 error = mysql_bin_log.rollback(thd, all);
2706 8016 return error;
2707 8017 }
2708
2709 /**
2710 Write a rollback record of the transaction to the binary log.
2711
2712 For binary log group commit, the rollback is separated into three
2713 parts:
2714
2715 1. First part consists of filling the necessary caches and
2716 finalizing them (if they need to be finalized). After a cache is
2717 finalized, nothing can be added to the cache.
2718
2719 2. Second part execute an ordered flush and commit. This will be
2720 done using the group commit functionality in @c ordered_commit.
2721
2722 Since we roll back the transaction early, we call @c
2723 ordered_commit with the @c skip_commit flag set. The @c
2724 ha_commit_low call inside @c ordered_commit will then not be
2725 called.
2726
2727 3. Third part checks any errors resulting from the flush and handles
2728 them appropriately.
2729
2730 @see MYSQL_BIN_LOG::ordered_commit
2731 @see ha_commit_low
2732 @see ha_rollback_low
2733
2734 @param thd Session to commit
2735 @param all This is @c true if this is a real transaction rollback, and
2736 @c false otherwise.
2737
2738 @return Error code, or zero if there were no error.
2739 */
2740
2741 1838813 int MYSQL_BIN_LOG::rollback(THD *thd, bool all) {
2742 1838813 int error = 0;
2743 1838813 bool stuff_logged = false;
2744
1/2
✓ Branch 0 taken 1839592 times.
✗ Branch 1 not taken.
1838813 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
2745 1839592 bool is_empty = false;
2746
2747
1/2
✓ Branch 0 taken 1839568 times.
✗ Branch 1 not taken.
1839592 DBUG_TRACE;
2748
10/14
✓ Branch 0 taken 1839570 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1839449 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 1839443 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 3 times.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
1839568 DBUG_PRINT("enter",
2749 ("all: %s, cache_mngr: 0x%llx, thd->is_error: %s", YESNO(all),
2750 (ulonglong)cache_mngr, YESNO(thd->is_error())));
2751 /*
2752 Defer XA-transaction rollback until its XA-rollback event is recorded.
2753 When we are executing a ROLLBACK TO SAVEPOINT, we
2754 should only clear the caches since this function is called as part
2755 of the engine rollback.
2756 In other cases we roll back the transaction in the engines early
2757 since this will release locks and allow other transactions to
2758 start executing.
2759 */
2760
3/4
✓ Branch 0 taken 1839404 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 239 times.
✓ Branch 3 taken 1839165 times.
1839449 if (is_xa_rollback(thd)) {
2761 239 auto xs = thd->get_transaction()->xid_state();
2762
2763
7/10
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
239 assert(all || !xs->is_binlogged() ||
2764 (!xs->is_detached() && thd->is_error()));
2765
2766 239 is_empty = !xs->is_binlogged();
2767
2768
2/4
✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 239 times.
239 if ((error = this->write_xa_to_cache(thd)) != 0) goto end;
2769
2770
1/2
✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
239 cache_mngr = thd_get_cache_mngr(thd);
2771 #ifdef WITH_WSREP
2772 /*
2773 BF aborted THD may have dandling sql_command set to
2774 SQLCOM_ROLLBACK_TO_SAVEPOINT, don't care about it, as we have to BF abort
2775 this one
2776 */
2777 } else if (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT ||
2778
3/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 1839112 times.
✓ Branch 2 taken 1839030 times.
✗ Branch 3 not taken.
1839055 thd->wsrep_trx().state() == wsrep::transaction::s_aborting ||
2779
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 49 times.
53 thd->wsrep_force_savept_rollback) {
2780 #else
2781 } else if (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT) {
2782 #endif /* WITH_WSREP */
2783 /*
2784 Reset binlog_snapshot_% variables for the current connection so that the
2785 current coordinates are shown after committing a consistent snapshot
2786 transaction.
2787 */
2788
2/2
✓ Branch 0 taken 228354 times.
✓ Branch 1 taken 1610676 times.
1839030 if (cache_mngr != nullptr) {
2789
1/2
✓ Branch 0 taken 228355 times.
✗ Branch 1 not taken.
228354 mysql_mutex_lock(&thd->LOCK_thd_data);
2790 228355 cache_mngr->drop_consistent_snapshot();
2791
1/2
✓ Branch 0 taken 228417 times.
✗ Branch 1 not taken.
228380 mysql_mutex_unlock(&thd->LOCK_thd_data);
2792 }
2793
2/4
✓ Branch 0 taken 1837928 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1837928 times.
1839093 if ((error = trx_coordinator::rollback_in_engines(thd, all))) goto end;
2794 }
2795
2796 /*
2797 If there is no cache manager, or if there is nothing in the
2798 caches, there are no caches to roll back, so we're trivially done
2799 unless XA-ROLLBACK that yet to run rollback_low().
2800 */
2801
7/8
✓ Branch 0 taken 228551 times.
✓ Branch 1 taken 1609588 times.
✓ Branch 2 taken 228614 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 218995 times.
✓ Branch 5 taken 9619 times.
✓ Branch 6 taken 1828937 times.
✓ Branch 7 taken 9265 times.
1838139 if (cache_mngr == nullptr || cache_mngr->is_binlog_empty()) {
2802 1828937 goto end;
2803 }
2804
2805
3/14
✓ Branch 0 taken 9619 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9618 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9618 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
9265 DBUG_PRINT("debug", ("all.cannot_safely_rollback(): %s, trx_cache_empty: %s",
2806 YESNO(thd->get_transaction()->cannot_safely_rollback(
2807 Transaction_ctx::SESSION)),
2808 YESNO(cache_mngr->trx_cache.is_binlog_empty())));
2809
3/14
✓ Branch 0 taken 9617 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9619 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9619 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
9618 DBUG_PRINT("debug",
2810 ("stmt.cannot_safely_rollback(): %s, stmt_cache_empty: %s",
2811 YESNO(thd->get_transaction()->cannot_safely_rollback(
2812 Transaction_ctx::STMT)),
2813 YESNO(cache_mngr->stmt_cache.is_binlog_empty())));
2814
2815 /*
2816 If an incident event is set we do not flush the content of the statement
2817 cache because it may be corrupted.
2818 */
2819
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 9611 times.
9619 if (cache_mngr->stmt_cache.has_incident()) {
2820 7 const char *err_msg =
2821 "The content of the statement cache is corrupted "
2822 "while writing a rollback record of the transaction "
2823 "to the binary log.";
2824
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error = write_incident(thd, true /*need_lock_log=true*/, err_msg);
2825
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 cache_mngr->stmt_cache.reset();
2826
3/4
✓ Branch 0 taken 9612 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 825 times.
✓ Branch 3 taken 8787 times.
9611 } else if (!cache_mngr->stmt_cache.is_binlog_empty()) {
2827 1671 if (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
2828
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
21 !thd->lex->query_block->field_list_is_empty() && /* With select */
2829
6/8
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 804 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 21 times.
✓ Branch 7 taken 804 times.
867 !(thd->lex->create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
2830 21 thd->is_current_stmt_binlog_format_row()) {
2831 /*
2832 In row based binlog format, we reset the binlog statement cache
2833 when rolling back a single statement 'CREATE...SELECT' transaction,
2834 since the 'CREATE TABLE' event was put in the binlog statement cache.
2835 */
2836
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 cache_mngr->stmt_cache.reset();
2837 } else {
2838
2/4
✓ Branch 0 taken 804 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 804 times.
804 if ((error = cache_mngr->stmt_cache.finalize(thd))) goto end;
2839 804 stuff_logged = true;
2840 }
2841 }
2842
2843
3/4
✓ Branch 0 taken 9616 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5179 times.
✓ Branch 3 taken 4437 times.
9619 if (ending_trans(thd, all)) {
2844
3/4
✓ Branch 0 taken 5178 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 482 times.
✓ Branch 3 taken 4696 times.
5179 if (trans_cannot_safely_rollback(thd)) {
2845 482 auto xs = thd->get_transaction()->xid_state();
2846
1/2
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
482 std::string query{"ROLLBACK"};
2847
2848
2/4
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 482 times.
482 if (is_xa_rollback(thd)) {
2849 /* this block is relevant only for not prepared yet and "local" xa trx
2850 */
2851 assert(
2852 thd->get_transaction()->xid_state()->has_state(XID_STATE::XA_IDLE));
2853
2854 std::ostringstream oss;
2855 oss << "XA ROLLBACK " << *xs->get_xid() << std::flush;
2856 query = oss.str();
2857 }
2858 /*
2859 If the transaction is being rolled back and contains changes that
2860 cannot be rolled back, the trx-cache's content is flushed.
2861 */
2862 482 Query_log_event end_evt(thd, query.data(), query.length(), true, false,
2863
1/2
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
964 true, 0, true);
2864 964 error = thd->lex->sql_command != SQLCOM_XA_ROLLBACK
2865
2/4
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 482 times.
✗ Branch 3 not taken.
482 ? cache_mngr->trx_cache.finalize(thd, &end_evt)
2866 : cache_mngr->trx_cache.finalize(thd, &end_evt, xs);
2867 482 stuff_logged = true;
2868 482 } else {
2869 /*
2870 If the transaction is being rolled back and its changes can be
2871 rolled back, the trx-cache's content is truncated.
2872 */
2873
1/2
✓ Branch 0 taken 4696 times.
✗ Branch 1 not taken.
4696 error = cache_mngr->trx_cache.truncate(thd, all);
2874
2875
4/6
✓ Branch 0 taken 4697 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4695 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
4696 DBUG_EXECUTE_IF("ensure_binlog_cache_is_reset", {
2876 /* Assert that binlog cache is reset at rollback time. */
2877 assert(binlog_cache_is_reset);
2878 binlog_cache_is_reset = false;
2879 };);
2880 }
2881 } else {
2882 /*
2883 If a statement is being rolled back, it is necessary to know
2884 exactly why a statement may not be safely rolled back as in
2885 some specific situations the trx-cache can be truncated.
2886
2887 If a temporary table is created or dropped, the trx-cache is not
2888 truncated. Note that if the stmt-cache is used, there is nothing
2889 to truncate in the trx-cache.
2890
2891 If a non-transactional table is updated and the binlog format is
2892 statement, the trx-cache is not truncated. The trx-cache is used
2893 when the direct option is off and a transactional table has been
2894 updated before the current statement in the context of the
2895 current transaction. Note that if the stmt-cache is used there is
2896 nothing to truncate in the trx-cache.
2897
2898 If other binlog formats are used, updates to non-transactional
2899 tables are written to the stmt-cache and trx-cache can be safely
2900 truncated, if necessary.
2901 */
2902
1/2
✓ Branch 0 taken 4433 times.
✗ Branch 1 not taken.
8869 if (thd->get_transaction()->has_dropped_temp_table(Transaction_ctx::STMT) ||
2903
5/6
✓ Branch 0 taken 4435 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 630 times.
✓ Branch 3 taken 3807 times.
✓ Branch 4 taken 293 times.
✓ Branch 5 taken 4143 times.
9501 thd->get_transaction()->has_created_temp_table(Transaction_ctx::STMT) ||
2904 4433 (thd->get_transaction()->has_modified_non_trans_table(
2905 630 Transaction_ctx::STMT) &&
2906
2/2
✓ Branch 0 taken 294 times.
✓ Branch 1 taken 336 times.
630 thd->variables.binlog_format == BINLOG_FORMAT_STMT)) {
2907 /*
2908 If the statement is being rolled back and dropped or created a
2909 temporary table or modified a non-transactional table and the
2910 statement-based replication is in use, the statement's changes
2911 in the trx-cache are preserved.
2912 */
2913
1/2
✓ Branch 0 taken 293 times.
✗ Branch 1 not taken.
293 cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
2914 } else {
2915 /*
2916 Otherwise, the statement's changes in the trx-cache are
2917 truncated.
2918 */
2919
1/2
✓ Branch 0 taken 4146 times.
✗ Branch 1 not taken.
4143 error = cache_mngr->trx_cache.truncate(thd, all);
2920 }
2921 }
2922
2/2
✓ Branch 0 taken 1286 times.
✓ Branch 1 taken 8332 times.
9618 if (stuff_logged) {
2923 1286 Transaction_ctx *trn_ctx = thd->get_transaction();
2924
1/2
✓ Branch 0 taken 1286 times.
✗ Branch 1 not taken.
1286 trn_ctx->store_commit_parent(
2925 m_dependency_tracker.get_max_committed_timestamp());
2926 }
2927
2928
3/8
✓ Branch 0 taken 9609 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9618 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9618 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9618 DBUG_PRINT("debug", ("error: %d", error));
2929
4/4
✓ Branch 0 taken 9617 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1286 times.
✓ Branch 3 taken 8331 times.
9618 if (error == 0 && stuff_logged) {
2930
2/4
✓ Branch 0 taken 1286 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1286 times.
✗ Branch 3 not taken.
1286 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_invoke_before_commit_hook");
2931
7/12
✓ Branch 0 taken 1286 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1268 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1286 times.
1286 if (RUN_HOOK(
2932 transaction, before_commit,
2933 (thd, all, thd_get_cache_mngr(thd)->get_trx_cache(),
2934 thd_get_cache_mngr(thd)->get_stmt_cache(),
2935 max<my_off_t>(max_binlog_cache_size, max_binlog_stmt_cache_size),
2936 false))) {
2937 // Reset the thread OK status before changing the outcome.
2938 if (thd->get_stmt_da()->is_ok())
2939 thd->get_stmt_da()->reset_diagnostics_area();
2940 my_error(ER_RUN_HOOK_ERROR, MYF(0), "before_commit");
2941 return RESULT_ABORTED;
2942 }
2943 // XA rollback is always accepted.
2944
2/4
✓ Branch 0 taken 1286 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1286 times.
1286 assert(!thd->get_transaction()
2945 ->get_rpl_transaction_ctx()
2946 ->is_transaction_rollback());
2947
2948
1/2
✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
1286 error = ordered_commit(thd, all, /* skip_commit */ true);
2949
2950 // Inform hook listeners that a XA ROLLBACK did commit, that
2951 // is, did log a transaction to the binary log.
2952
6/8
✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 143 times.
✓ Branch 5 taken 1140 times.
✓ Branch 6 taken 143 times.
✓ Branch 7 taken 1140 times.
1283 if (!error && is_xa_rollback(thd))
2953
4/6
✓ Branch 0 taken 143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 126 times.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
143 (void)RUN_HOOK(transaction, after_commit, (thd, all));
2954 }
2955
2956 #ifdef WITH_WSREP
2957
13/16
✓ Branch 0 taken 9608 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 673 times.
✓ Branch 3 taken 8935 times.
✓ Branch 4 taken 673 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 673 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 648 times.
✓ Branch 9 taken 25 times.
✓ Branch 10 taken 9588 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 107 times.
✓ Branch 13 taken 9481 times.
✓ Branch 14 taken 9506 times.
✓ Branch 15 taken 107 times.
9615 if (!WSREP_EMULATE_BINLOG(thd) && check_write_error(thd)) {
2958 #else
2959 if (check_write_error(thd)) {
2960 #endif /* WITH_WSREP */
2961 /*
2962 We reach this point if the effect of a statement did not properly get into
2963 a cache and need to be rolled back.
2964 */
2965
1/2
✓ Branch 0 taken 107 times.
✗ Branch 1 not taken.
107 error |= cache_mngr->trx_cache.truncate(thd, all);
2966 }
2967
2968 9506 end:
2969 // The caches may be empty if an `XA ROLLBACK` was issued just after `XA
2970 // END`. In that case, the BCG will not be invoked and we need to
2971 // rollback in SEs and finalize GTID state.
2972
9/10
✓ Branch 0 taken 1838273 times.
✓ Branch 1 taken 277 times.
✓ Branch 2 taken 1837041 times.
✓ Branch 3 taken 1232 times.
✓ Branch 4 taken 1837202 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 93 times.
✓ Branch 7 taken 1837109 times.
✓ Branch 8 taken 93 times.
✓ Branch 9 taken 1838618 times.
1838550 if (!error && !stuff_logged && is_xa_rollback(thd)) {
2973
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 error = trx_coordinator::rollback_in_engines(thd, all);
2974
6/8
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 93 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 66 times.
✓ Branch 7 taken 27 times.
93 if (!error && !thd->is_error()) {
2975 /*
2976 XA-rollback ignores the gtid_state, if the transaciton
2977 is empty.
2978 */
2979
4/6
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
66 if (is_empty && !thd->slave_thread) gtid_state->update_on_rollback(thd);
2980 /*
2981 XA-rollback commits the new gtid_state, if transaction
2982 is not empty.
2983 */
2984 else {
2985
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 gtid_state->update_on_commit(thd);
2986 /*
2987 Inform hook listeners that a XA ROLLBACK did commit, that
2988 is, did log a transaction to the binary log.
2989 */
2990
2/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6 (void)RUN_HOOK(transaction, after_commit, (thd, all));
2991 }
2992 }
2993 }
2994 /*
2995 When a statement errors out on auto-commit mode it is rollback
2996 implicitly, so the same should happen to its GTID.
2997 */
2998
2/2
✓ Branch 0 taken 1826805 times.
✓ Branch 1 taken 11842 times.
1838711 if (!thd->in_active_multi_stmt_transaction())
2999
1/2
✓ Branch 0 taken 1828152 times.
✗ Branch 1 not taken.
1826805 gtid_state->update_on_rollback(thd);
3000
3001 /*
3002 TODO: some errors are overwritten, which may cause problem,
3003 fix it later.
3004 */
3005
5/8
✓ Branch 0 taken 1839590 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1839287 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 1839281 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
1839994 DBUG_PRINT("return", ("error: %d", error));
3006 1839289 return error;
3007 1839289 }
3008
3009 /**
3010 @note
3011 How do we handle this (unlikely but legal) case:
3012 @verbatim
3013 [transaction] + [update to non-trans table] + [rollback to savepoint] ?
3014 @endverbatim
3015 The problem occurs when a savepoint is before the update to the
3016 non-transactional table. Then when there's a rollback to the savepoint, if we
3017 simply truncate the binlog cache, we lose the part of the binlog cache where
3018 the update is. If we want to not lose it, we need to write the SAVEPOINT
3019 command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
3020 is easy: it's just write at the end of the binlog cache, but the former
3021 should be *inserted* to the place where the user called SAVEPOINT. The
3022 solution is that when the user calls SAVEPOINT, we write it to the binlog
3023 cache (so no need to later insert it). As transactions are never intermixed
3024 in the binary log (i.e. they are serialized), we won't have conflicts with
3025 savepoint names when using mysqlbinlog or in the slave SQL thread.
3026 Then when ROLLBACK TO SAVEPOINT is called, if we updated some
3027 non-transactional table, we don't truncate the binlog cache but instead write
3028 ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
3029 will chop the SAVEPOINT command from the binlog cache, which is good as in
3030 that case there is no need to have it in the binlog).
3031 */
3032
3033 7894 static int binlog_savepoint_set(handlerton *, THD *thd, void *sv) {
3034
1/2
✓ Branch 0 taken 7895 times.
✗ Branch 1 not taken.
7894 DBUG_TRACE;
3035 7895 int error = 1;
3036
3037 #ifdef WITH_WSREP
3038 /*
3039 Clear table maps before writing SAVEPOINT event. This enforces
3040 recreation of table map events for the following row event.
3041 */
3042 7895 thd->clear_binlog_table_maps();
3043 #endif /* WITH_WSREP */
3044
3045 7894 String log_query;
3046
2/4
✓ Branch 0 taken 7894 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7894 times.
7894 if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")))
3047 return error;
3048 else
3049 7894 append_identifier(thd, &log_query, thd->lex->ident.str,
3050
1/2
✓ Branch 0 taken 7895 times.
✗ Branch 1 not taken.
7894 thd->lex->ident.length);
3051
3052
1/2
✓ Branch 0 taken 7895 times.
✗ Branch 1 not taken.
7895 int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
3053
1/2
✓ Branch 0 taken 7895 times.
✗ Branch 1 not taken.
7895 Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), true,
3054
1/2
✓ Branch 0 taken 7895 times.
✗ Branch 1 not taken.
15790 false, true, errcode);
3055 /*
3056 We cannot record the position before writing the statement
3057 because a rollback to a savepoint (.e.g. consider it "S") would
3058 prevent the savepoint statement (i.e. "SAVEPOINT S") from being
3059 written to the binary log despite the fact that the server could
3060 still issue other rollback statements to the same savepoint (i.e.
3061 "S").
3062 Given that the savepoint is valid until the server releases it,
3063 ie, until the transaction commits or it is released explicitly,
3064 we need to log it anyway so that we don't have "ROLLBACK TO S"
3065 or "RELEASE S" without the preceding "SAVEPOINT S" in the binary
3066 log.
3067 */
3068
2/4
✓ Branch 0 taken 7894 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7894 times.
✗ Branch 3 not taken.
7895 if (!(error = mysql_bin_log.write_event(&qinfo)))
3069
1/2
✓ Branch 0 taken 7895 times.
✗ Branch 1 not taken.
7894 binlog_trans_log_savepos(thd, (my_off_t *)sv);
3070
3071 7895 return error;
3072 7895 }
3073
3074 4053 static int binlog_savepoint_rollback(handlerton *, THD *thd, void *sv) {
3075
1/2
✓ Branch 0 taken 4053 times.
✗ Branch 1 not taken.
4053 DBUG_TRACE;
3076
1/2
✓ Branch 0 taken 4053 times.
✗ Branch 1 not taken.
4053 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
3077 4053 my_off_t pos = *(my_off_t *)sv;
3078
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4053 times.
4053 assert(pos != ~(my_off_t)0);
3079
3080 /*
3081 Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
3082 non-transactional table. Otherwise, truncate the binlog cache starting
3083 from the SAVEPOINT command.
3084 */
3085 #ifdef WITH_WSREP
3086 /*
3087 For streaming replication, we must replicate savepoint rollback so that
3088 slaves can maintain SR transactions
3089 */
3090
7/8
✓ Branch 0 taken 4050 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4050 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 4035 times.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 4035 times.
4053 if (thd->wsrep_trx().is_streaming() || trans_cannot_safely_rollback(thd)) {
3091 #else
3092 if (trans_cannot_safely_rollback(thd)) {
3093 #endif /* WITH_WSREP */
3094 18 String log_query;
3095
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
18 if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")))
3096 return 1;
3097 else {
3098 /*
3099 Before writing identifier to the binlog, make sure to
3100 quote the identifier properly so as to prevent any SQL
3101 injection on the slave.
3102 */
3103 18 append_identifier(thd, &log_query, thd->lex->ident.str,
3104
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 thd->lex->ident.length);
3105 }
3106
3107
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
3108
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), true,
3109
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 false, true, errcode);
3110
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 return mysql_bin_log.write_event(&qinfo);
3111 18 }
3112 // Otherwise, we truncate the cache
3113
1/2
✓ Branch 0 taken 4035 times.
✗ Branch 1 not taken.
4035 cache_mngr->trx_cache.restore_savepoint(pos);
3114 /*
3115 When a SAVEPOINT is executed inside a stored function/trigger we force the
3116 pending event to be flushed with a STMT_END_F flag and clear the table maps
3117 as well to ensure that following DMLs will have a clean state to start
3118 with. ROLLBACK inside a stored routine has to finalize possibly existing
3119 current row-based pending event with cleaning up table maps. That ensures
3120 that following DMLs will have a clean state to start with.
3121 */
3122
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4019 times.
4035 if (thd->in_sub_stmt) thd->clear_binlog_table_maps();
3123 4035 return 0;
3124 4053 }
3125
3126 /**
3127 purge logs, master and slave sides both, related error code
3128 converter.
3129 Called from @c purge_error_message(), @c MYSQL_BIN_LOG::reset_logs()
3130
3131 @param res an error code as used by purging routines
3132
3133 @return the user level error code ER_*
3134 */
3135 146 static uint purge_log_get_error_code(int res) {
3136 146 uint errcode = 0;
3137
3138
2/11
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
146 switch (res) {
3139 135 case 0:
3140 135 break;
3141 11 case LOG_INFO_EOF:
3142 11 errcode = ER_UNKNOWN_TARGET_BINLOG;
3143 11 break;
3144 case LOG_INFO_IO:
3145 errcode = ER_IO_ERR_LOG_INDEX_READ;
3146 break;
3147 case LOG_INFO_INVALID:
3148 errcode = ER_BINLOG_PURGE_PROHIBITED;
3149 break;
3150 case LOG_INFO_SEEK:
3151 errcode = ER_FSEEK_FAIL;
3152 break;
3153 case LOG_INFO_MEM:
3154 errcode = ER_OUT_OF_RESOURCES;
3155 break;
3156 case LOG_INFO_FATAL:
3157 errcode = ER_BINLOG_PURGE_FATAL_ERR;
3158 break;
3159 case LOG_INFO_IN_USE:
3160 errcode = ER_LOG_IN_USE;
3161 break;
3162 case LOG_INFO_EMFILE:
3163 errcode = ER_BINLOG_PURGE_EMFILE;
3164 break;
3165 case LOG_INFO_BACKUP_LOCK:
3166 errcode = ER_CANNOT_PURGE_BINLOG_WITH_BACKUP_LOCK;
3167 break;
3168 default:
3169 errcode = ER_LOG_PURGE_UNKNOWN_ERR;
3170 break;
3171 }
3172
3173 146 return errcode;
3174 }
3175
3176 /**
3177 Check whether binlog state allows to safely release MDL locks after
3178 rollback to savepoint.
3179
3180 @param thd The client thread that executes the transaction.
3181
3182 @return true - It is safe to release MDL locks.
3183 false - If it is not.
3184 */
3185 4046 static bool binlog_savepoint_rollback_can_release_mdl(handlerton *, THD *thd) {
3186
1/2
✓ Branch 0 taken 4046 times.
✗ Branch 1 not taken.
4046 DBUG_TRACE;
3187 /**
3188 If we have not updated any non-transactional tables rollback
3189 to savepoint will simply truncate binlog cache starting from
3190 SAVEPOINT command. So it should be safe to release MDL acquired
3191 after SAVEPOINT command in this case.
3192 */
3193
1/2
✓ Branch 0 taken 4046 times.
✗ Branch 1 not taken.
8092 return !trans_cannot_safely_rollback(thd);
3194 4046 }
3195
3196 /**
3197 Adjust log offset in the binary log file for all running slaves
3198 This class implements call back function for do_for_all_thd().
3199 It is called for each thd in thd list to adjust offset.
3200 */
3201 class Adjust_offset : public Do_THD_Impl {
3202 public:
3203 207 Adjust_offset(my_off_t value) : m_purge_offset(value) {}
3204 866 void operator()(THD *thd) override {
3205 LOG_INFO *linfo;
3206 866 mysql_mutex_lock(&thd->LOCK_thd_data);
3207
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 783 times.
866 if ((linfo = thd->current_linfo)) {
3208 /*
3209 Index file offset can be less that purge offset only if
3210 we just started reading the index file. In that case
3211 we have nothing to adjust.
3212 */
3213
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 81 times.
83 if (linfo->index_file_offset < m_purge_offset)
3214 2 linfo->fatal = (linfo->index_file_offset != 0);
3215 else
3216 81 linfo->index_file_offset -= m_purge_offset;
3217 }
3218 866 mysql_mutex_unlock(&thd->LOCK_thd_data);
3219 866 }
3220
3221 private:
3222 my_off_t m_purge_offset;
3223 };
3224
3225 /*
3226 Adjust the position pointer in the binary log file for all running slaves.
3227
3228 SYNOPSIS
3229 adjust_linfo_offsets()
3230 purge_offset Number of bytes removed from start of log index file
3231
3232 NOTES
3233 - This is called when doing a PURGE when we delete lines from the
3234 index log file.
3235
3236 REQUIREMENTS
3237 - Before calling this function, we have to ensure that no threads are
3238 using any binary log file before purge_offset.
3239
3240 TODO
3241 - Inform the slave threads that they should sync the position
3242 in the binary log file with flush_relay_log_info.
3243 Now they sync is done for next read.
3244 */
3245 207 static void adjust_linfo_offsets(my_off_t purge_offset) {
3246
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 Adjust_offset adjust_offset(purge_offset);
3247
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 Global_THD_manager::get_instance()->do_for_all_thd(&adjust_offset);
3248 207 }
3249
3250 /**
3251 This class implements Call back function for do_for_all_thd().
3252 It is called for each thd in thd list to count
3253 threads using bin log file
3254 */
3255
3256 class Log_in_use : public Do_THD_Impl {
3257 public:
3258 15204 Log_in_use(const char *value) : m_log_name(value), m_count(0) {
3259 15204 m_log_name_len = strlen(m_log_name) + 1;
3260 15204 }
3261 164756 void operator()(THD *thd) override {
3262 LOG_INFO *linfo;
3263 164756 mysql_mutex_lock(&thd->LOCK_thd_data);
3264
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 164519 times.
164756 if ((linfo = thd->current_linfo)) {
3265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (!strncmp(m_log_name, linfo->log_file_name, m_log_name_len)) {
3266 LogErr(WARNING_LEVEL, ER_BINLOG_FILE_BEING_READ_NOT_PURGED, m_log_name,
3267 thd->thread_id());
3268 m_count++;
3269 }
3270 }
3271 164756 mysql_mutex_unlock(&thd->LOCK_thd_data);
3272 164756 }
3273 15204 int get_count() { return m_count; }
3274
3275 private:
3276 const char *m_log_name;
3277 size_t m_log_name_len;
3278 int m_count;
3279 };
3280
3281 15204 static int log_in_use(const char *log_name) {
3282
1/2
✓ Branch 0 taken 15204 times.
✗ Branch 1 not taken.
15204 Log_in_use log_in_use(log_name);
3283 #ifndef NDEBUG
3284
3/4
✓ Branch 0 taken 15204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14974 times.
✓ Branch 3 taken 230 times.
15204 if (current_thd)
3285
3/6
✓ Branch 0 taken 14974 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14974 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14974 times.
✗ Branch 5 not taken.
14974 DEBUG_SYNC(current_thd, "purge_logs_after_lock_index_before_thread_count");
3286 #endif
3287
1/2
✓ Branch 0 taken 15204 times.
✗ Branch 1 not taken.
15204 Global_THD_manager::get_instance()->do_for_all_thd(&log_in_use);
3288 30408 return log_in_use.get_count();
3289 15204 }
3290
3291 137 static bool purge_error_message(THD *thd, int res) {
3292 uint errcode;
3293
3294
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 135 times.
137 if ((errcode = purge_log_get_error_code(res)) != 0) {
3295 2 my_error(errcode, MYF(0));
3296 2 return true;
3297 }
3298 135 my_ok(thd);
3299 135 return false;
3300 }
3301
3302 278 bool is_transaction_empty(THD *thd) {
3303
1/2
✓ Branch 0 taken 278 times.
✗ Branch 1 not taken.
278 DBUG_TRACE;
3304
1/2
✓ Branch 0 taken 278 times.
✗ Branch 1 not taken.
278 int rw_ha_count = check_trx_rw_engines(thd, Transaction_ctx::SESSION);
3305
1/2
✓ Branch 0 taken 278 times.
✗ Branch 1 not taken.
278 rw_ha_count += check_trx_rw_engines(thd, Transaction_ctx::STMT);
3306 278 return rw_ha_count == 0;
3307 278 }
3308
3309 556 int check_trx_rw_engines(THD *thd, Transaction_ctx::enum_trx_scope trx_scope) {
3310
1/2
✓ Branch 0 taken 556 times.
✗ Branch 1 not taken.
556 DBUG_TRACE;
3311
3312 556 int rw_ha_count = 0;
3313
1/2
✓ Branch 0 taken 556 times.
✗ Branch 1 not taken.
556 auto ha_list = thd->get_transaction()->ha_trx_info(trx_scope);
3314
3315
7/12
✓ Branch 0 taken 556 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 556 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 477 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 477 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1033 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 477 times.
✓ Branch 11 taken 556 times.
1033 for (auto const &ha_info : ha_list) {
3316
2/4
✓ Branch 0 taken 477 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 477 times.
✗ Branch 3 not taken.
477 if (ha_info.is_trx_read_write()) ++rw_ha_count;
3317 556 }
3318 556 return rw_ha_count;
3319 556 }
3320
3321 884 bool is_empty_transaction_in_binlog_cache(const THD *thd) {
3322
1/2
✓ Branch 0 taken 884 times.
✗ Branch 1 not taken.
884 DBUG_TRACE;
3323
3324
1/2
✓ Branch 0 taken 884 times.
✗ Branch 1 not taken.
884 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
3325
6/8
✓ Branch 0 taken 884 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 884 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 874 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 874 times.
884 if (cache_mngr != nullptr && cache_mngr->has_empty_transaction()) {
3326 10 return true;
3327 }
3328
3329 874 return false;
3330 884 }
3331
3332 /**
3333 This function checks if a transactional table was updated by the
3334 current transaction.
3335
3336 @param thd The client thread that executed the current statement.
3337 @return
3338 @c true if a transactional table was updated, @c false otherwise.
3339 */
3340 24035911 bool trans_has_updated_trans_table(const THD *thd) {
3341 24035911 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
3342
3343
2/2
✓ Branch 0 taken 16678801 times.
✓ Branch 1 taken 7358870 times.
24037671 return (cache_mngr ? !cache_mngr->trx_cache.is_binlog_empty() : 0);
3344 }
3345
3346 /**
3347 This function checks if a transactional table was updated by the
3348 current statement.
3349
3350 @param ha_list Registered storage engine handler list.
3351 @return
3352 @c true if a transactional table was updated, @c false otherwise.
3353 */
3354 3545152 bool stmt_has_updated_trans_table(Ha_trx_info_list const &ha_list) {
3355
7/12
✓ Branch 0 taken 3545287 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3545257 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5509816 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2390800 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5935979 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5509807 times.
✓ Branch 11 taken 426172 times.
5935954 for (auto const &ha_info : ha_list) {
3356
7/8
✓ Branch 0 taken 5509819 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5505993 times.
✓ Branch 3 taken 3826 times.
✓ Branch 4 taken 3119019 times.
✓ Branch 5 taken 2386976 times.
✓ Branch 6 taken 3119019 times.
✓ Branch 7 taken 2390802 times.
5509816 if (ha_info.is_trx_read_write() && ha_info.ht() != binlog_hton)
3357 3119019 return (true);
3358
4/4
✓ Branch 0 taken 426176 times.
✓ Branch 1 taken 3119009 times.
✓ Branch 2 taken 426372 times.
✓ Branch 3 taken 3119016 times.
6664200 }
3359 426372 return (false);
3360 }
3361
3362 /**
3363 This function checks if a transaction, either a multi-statement
3364 or a single statement transaction is about to commit or not.
3365
3366 @param thd The client thread that executed the current statement.
3367 @param all Committing a transaction (i.e. true) or a statement
3368 (i.e. false).
3369 @return
3370 @c true if committing a transaction, otherwise @c false.
3371 */
3372 18275746 bool ending_trans(THD *thd, const bool all) {
3373
4/4
✓ Branch 0 taken 14816396 times.
✓ Branch 1 taken 3459350 times.
✓ Branch 2 taken 3567803 times.
✓ Branch 3 taken 11248613 times.
18275746 return (all || ending_single_stmt_trans(thd, all));
3374 }
3375
3376 /**
3377 This function checks if a single statement transaction is about
3378 to commit or not.
3379
3380 @param thd The client thread that executed the current statement.
3381 @param all Committing a transaction (i.e. true) or a statement
3382 (i.e. false).
3383 @return
3384 @c true if committing a single statement transaction, otherwise
3385 @c false.
3386 */
3387 14816323 bool ending_single_stmt_trans(THD *thd, const bool all) {
3388
3/4
✓ Branch 0 taken 14816343 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3567752 times.
✓ Branch 3 taken 11248637 times.
14816323 return (!all && !thd->in_multi_stmt_transaction_mode());
3389 }
3390
3391 /**
3392 This function checks if a transaction cannot be rolled back safely.
3393
3394 @param thd The client thread that executed the current statement.
3395 @return
3396 @c true if cannot be safely rolled back, @c false otherwise.
3397 */
3398 13274 bool trans_cannot_safely_rollback(const THD *thd) {
3399 13274 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
3400
3401 13275 return cache_mngr->trx_cache.cannot_rollback();
3402 }
3403
3404 /**
3405 This function checks if current statement cannot be rollded back safely.
3406
3407 @param thd The client thread that executed the current statement.
3408 @return
3409 @c true if cannot be safely rolled back, @c false otherwise.
3410 */
3411 583665 bool stmt_cannot_safely_rollback(const THD *thd) {
3412 583665 return thd->get_transaction()->cannot_safely_rollback(Transaction_ctx::STMT);
3413 }
3414
3415 /**
3416 Execute a PURGE BINARY LOGS TO @<log@> command.
3417
3418 @param thd Pointer to THD object for the client thread executing the
3419 statement.
3420
3421 @param to_log Name of the last log to purge.
3422
3423 @retval false success
3424 @retval true failure
3425 */
3426 111 bool purge_source_logs_to_file(THD *thd, const char *to_log) {
3427 // first run the purge validations
3428
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 auto [is_invalid, invalid_error] = check_purge_conditions(mysql_bin_log);
3429
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
111 if (is_invalid) return purge_error_message(thd, invalid_error);
3430
3431 char search_file_name[FN_REFLEN];
3432 110 constexpr auto auto_purge{false};
3433 110 constexpr auto include_to_log{false};
3434 110 constexpr auto need_index_lock{true};
3435 110 constexpr auto need_update_threads{true};
3436
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 mysql_bin_log.make_log_name(search_file_name, to_log);
3437
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 auto purge_error = mysql_bin_log.purge_logs(
3438 search_file_name, include_to_log, need_index_lock, need_update_threads,
3439 nullptr, auto_purge);
3440
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 return purge_error_message(thd, purge_error);
3441 }
3442
3443 /**
3444 Execute a PURGE BINARY LOGS BEFORE @<date@> command.
3445
3446 @param thd Pointer to THD object for the client thread executing the
3447 statement.
3448
3449 @param purge_time Date before which logs should be purged.
3450
3451 @retval false success
3452 @retval true failure
3453 */
3454 26 bool purge_source_logs_before_date(THD *thd, time_t purge_time) {
3455 // first run the purge validations
3456 26 const auto [is_invalid, invalid_error] =
3457
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 check_purge_conditions(mysql_bin_log);
3458
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
26 if (is_invalid) return purge_error_message(thd, invalid_error);
3459
3460 // validations done, now purge
3461 25 constexpr auto auto_purge{false};
3462 auto purge_error =
3463
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 mysql_bin_log.purge_logs_before_date(purge_time, auto_purge);
3464
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 return purge_error_message(thd, purge_error);
3465 }
3466
3467 /**
3468 Check whether the instance is backup locked.
3469
3470 @retval 0 Instance is not backup locked
3471 @retval other Instance is backup locked or failure
3472 */
3473 7107 int check_instance_backup_locked() {
3474 7107 int res{0};
3475
3476 7107 auto is_instance_locked = is_instance_backup_locked(current_thd);
3477
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 7077 times.
✗ Branch 3 not taken.
7107 switch (is_instance_locked) {
3478 case Is_instance_backup_locked_result::OOM:
3479 res = LOG_INFO_MEM;
3480 break;
3481 30 case Is_instance_backup_locked_result::LOCKED:
3482 30 res = LOG_INFO_BACKUP_LOCK;
3483 30 break;
3484 7077 case Is_instance_backup_locked_result::NOT_LOCKED:
3485 7077 break;
3486 }
3487
3488 7107 return res;
3489 }
3490
3491 /*
3492 Helper function to get the error code of the query to be binlogged.
3493 */
3494 88703 int query_error_code(const THD *thd, bool not_killed) {
3495 int error;
3496
3497
2/2
✓ Branch 0 taken 88686 times.
✓ Branch 1 taken 17 times.
88703 if (not_killed) {
3498
2/2
✓ Branch 0 taken 876 times.
✓ Branch 1 taken 87811 times.
88686 error = thd->is_error() ? thd->get_stmt_da()->mysql_errno() : 0;
3499
3500 /* thd->get_stmt_da()->sql_errno() might be ER_SERVER_SHUTDOWN or
3501 ER_QUERY_INTERRUPTED, So here we need to make sure that error
3502 is not set to these errors when specified not_killed by the
3503 caller.
3504 */
3505
2/4
✓ Branch 0 taken 88687 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88687 times.
88687 if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED) error = 0;
3506 } else
3507 17 error = thd->killed;
3508
3509 88704 return error;
3510 }
3511
3512 /**
3513 Copy content of 'from' file from offset to 'to' file.
3514
3515 - We do the copy outside of the IO_CACHE as the cache
3516 buffers would just make things slower and more complicated.
3517 In most cases the copy loop should only do one read.
3518
3519 @param from File to copy.
3520 @param to File to copy to.
3521 @param offset Offset in 'from' file.
3522
3523
3524 @retval
3525 0 ok
3526 @retval
3527 -1 error
3528 */
3529 102886 static bool copy_file(IO_CACHE *from, IO_CACHE *to, my_off_t offset) {
3530 int bytes_read;
3531 uchar io_buf[IO_SIZE * 2];
3532
1/2
✓ Branch 0 taken 102886 times.
✗ Branch 1 not taken.
102886 DBUG_TRACE;
3533
3534
1/2
✓ Branch 0 taken 102886 times.
✗ Branch 1 not taken.
102886 mysql_file_seek(from->file, offset, MY_SEEK_SET, MYF(0));
3535 while (true) {
3536
1/2
✓ Branch 0 taken 175651 times.
✗ Branch 1 not taken.
175651 if ((bytes_read = (int)mysql_file_read(from->file, io_buf, sizeof(io_buf),
3537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 175651 times.
175651 MYF(MY_WME))) < 0)
3538 goto err;
3539
2/4
✓ Branch 0 taken 175651 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 175651 times.
175651 if (DBUG_EVALUATE_IF("fault_injection_copy_part_file", 1, 0))
3540 bytes_read = bytes_read / 2;
3541
2/2
✓ Branch 0 taken 102885 times.
✓ Branch 1 taken 72766 times.
175651 if (!bytes_read) break; // end of file
3542
3/4
✓ Branch 0 taken 72766 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 72765 times.
72766 if (mysql_file_write(to->file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
3543 1 goto err;
3544 }
3545
3546 102885 return false;
3547
3548 1 err:
3549 1 return true;
3550 102886 }
3551
3552 /**
3553 Load data's io cache specific hook to be executed
3554 before a chunk of data is being read into the cache's buffer
3555 The function instantiates and writes into the binlog
3556 replication events along LOAD DATA processing.
3557
3558 @param file pointer to io-cache
3559 @retval 0 success
3560 @retval 1 failure
3561 */
3562 128068 int log_loaded_block(IO_CACHE *file) {
3563
1/2
✓ Branch 0 taken 128069 times.
✗ Branch 1 not taken.
128068 DBUG_TRACE;
3564 LOAD_FILE_INFO *lf_info;
3565 uint block_len;
3566 /* buffer contains position where we started last read */
3567 128069 uchar *buffer = (uchar *)my_b_get_buffer_start(file);
3568
1/2
✓ Branch 0 taken 128069 times.
✗ Branch 1 not taken.
128069 uint max_event_size = current_thd->variables.max_allowed_packet;
3569 128069 lf_info = (LOAD_FILE_INFO *)file->arg;
3570
2/2
✓ Branch 0 taken 115916 times.
✓ Branch 1 taken 12152 times.
128069 if (lf_info->thd->is_current_stmt_binlog_format_row()) return 0;
3571
6/6
✓ Branch 0 taken 4098 times.
✓ Branch 1 taken 8054 times.
✓ Branch 2 taken 4008 times.
✓ Branch 3 taken 90 times.
✓ Branch 4 taken 4008 times.
✓ Branch 5 taken 8144 times.
16250 if (lf_info->last_pos_in_file != HA_POS_ERROR &&
3572 4098 lf_info->last_pos_in_file >= my_b_get_pos_in_file(file))
3573 4008 return 0;
3574
3575
2/2
✓ Branch 0 taken 4120 times.
✓ Branch 1 taken 8144 times.
12264 for (block_len = (uint)(my_b_get_bytes_in_buffer(file)); block_len > 0;
3576 4120 buffer += min(block_len, max_event_size),
3577 4120 block_len -= min(block_len, max_event_size)) {
3578 4120 lf_info->last_pos_in_file = my_b_get_pos_in_file(file);
3579
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 4027 times.
4120 if (lf_info->logged_data_file) {
3580 186 Append_block_log_event a(lf_info->thd, lf_info->thd->db().str, buffer,
3581 93 min(block_len, max_event_size),
3582
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 lf_info->log_delayed);
3583
2/4
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 93 times.
93 if (mysql_bin_log.write_event(&a)) return 1;
3584
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 } else {
3585 8054 Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db().str, buffer,
3586 4027 min(block_len, max_event_size),
3587
1/2
✓ Branch 0 taken 4027 times.
✗ Branch 1 not taken.
4027 lf_info->log_delayed);
3588
2/4
✓ Branch 0 taken 4027 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4027 times.
4027 if (mysql_bin_log.write_event(&b)) return 1;
3589 4027 lf_info->logged_data_file = true;
3590
1/2
✓ Branch 0 taken 4027 times.
✗ Branch 1 not taken.
4027 }
3591 }
3592 8144 return 0;
3593 128068 }
3594
3595 /* Helper function for SHOW BINLOG/RELAYLOG EVENTS */
3596 template <class BINLOG_FILE_READER>
3597 36092 bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log) {
3598 36092 Protocol *protocol = thd->get_protocol();
3599 36092 List<Item> field_list;
3600 36092 std::string errmsg;
3601 36092 LOG_INFO linfo;
3602
3603
1/2
✓ Branch 0 taken 18046 times.
✗ Branch 1 not taken.
36092 DBUG_TRACE;
3604
3605
3/4
✓ Branch 0 taken 1253 times.
✓ Branch 1 taken 16793 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1253 times.
36092 assert(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ||
3606 thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
3607
3608
2/2
✓ Branch 0 taken 18040 times.
✓ Branch 1 taken 6 times.
36092 if (binary_log->is_open()) {
3609 36080 LEX_MASTER_INFO *lex_mi = &thd->lex->mi;
3610 36080 Query_expression *unit = thd->lex->unit;
3611 ha_rows event_count, limit_start, limit_end;
3612 36080 my_off_t pos =
3613 36080 max<my_off_t>(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
3614 char search_file_name[FN_REFLEN], *name;
3615 36080 const char *log_file_name = lex_mi->log_file_name;
3616 36080 Log_event *ev = nullptr;
3617
3618
1/2
✓ Branch 0 taken 18040 times.
✗ Branch 1 not taken.
36080 unit->set_limit(thd, thd->lex->current_query_block());
3619 36080 limit_start = unit->offset_limit_cnt;
3620 36080 limit_end = unit->select_limit_cnt;
3621
3622 36080 name = search_file_name;
3623
2/2
✓ Branch 0 taken 14284 times.
✓ Branch 1 taken 3756 times.
36080 if (log_file_name)
3624
1/2
✓ Branch 0 taken 14284 times.
✗ Branch 1 not taken.
28568 binary_log->make_log_name(search_file_name, log_file_name);
3625 else
3626 7512 name = nullptr; // Find first log
3627
3628 36080 linfo.index_file_offset = 0;
3629
3630
3/4
✓ Branch 0 taken 18040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 18031 times.
36080 if (binary_log->find_log_pos(&linfo, name, true /*need_lock_index=true*/)) {
3631
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
18 errmsg = "Could not find target log";
3632 52 goto err;
3633 }
3634
3635
1/2
✓ Branch 0 taken 18031 times.
✗ Branch 1 not taken.
36062 mysql_mutex_lock(&thd->LOCK_thd_data);
3636 36062 thd->current_linfo = &linfo;
3637
1/2
✓ Branch 0 taken 18031 times.
✗ Branch 1 not taken.
36062 mysql_mutex_unlock(&thd->LOCK_thd_data);
3638
3639
1/2
✓ Branch 0 taken 18031 times.
✗ Branch 1 not taken.
36062 BINLOG_FILE_READER binlog_file_reader(
3640 opt_source_verify_checksum,
3641 36062 std::max(thd->variables.max_allowed_packet,
3642 36062 binlog_row_event_max_size + MAX_LOG_EVENT_HEADER));
3643
3644
3/4
✓ Branch 0 taken 18031 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 18014 times.
36062 if (binlog_file_reader.open(linfo.log_file_name, pos)) {
3645
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
34 errmsg = binlog_file_reader.get_error_str();
3646 34 goto err;
3647 }
3648
3649 /*
3650 Adjust the pos to the correct starting offset of an event after the
3651 specified position if it is an invalid starting offset.
3652 */
3653 36028 pos = binlog_file_reader.position();
3654
3655 /*
3656 For 'in-active' binlog file, it is safe to read all events in it. But
3657 for 'active' binlog file, it is only safe to read the events before
3658 get_binlog_end_pos().
3659
3660 Binlog rotation may happen after calling is_active(). In this case,
3661 end_pos will NOT be set to 0 while the file is actually not 'active'.
3662 It is safe, since 'end_pos' still expresses a correct position.
3663 */
3664 36028 my_off_t end_pos = binary_log->get_binlog_end_pos();
3665
3/4
✓ Branch 0 taken 18014 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 230 times.
✓ Branch 3 taken 17784 times.
36028 if (!binary_log->is_active(linfo.log_file_name)) end_pos = 0;
3666
3667
2/4
✓ Branch 0 taken 18014 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18014 times.
✗ Branch 3 not taken.
36028 DEBUG_SYNC(thd, "after_show_binlog_event_found_file");
3668
3669 /**
3670 Relaylog_file_reader and Binlog_file_reader are typedefs to
3671 Basic_binlog_file_reader whereas Relaylog_file_reader uses
3672 a Relaylog_ifile in the template instantiation and
3673 Binlog_file_reader uses a Binlog_ifile in the template
3674 instantiation.
3675
3676 Binlog_ifile and Relaylog_ifile differ only in the open()
3677 member function and they both derive from Basic_binlog_ifile.
3678
3679 Therefore, it is OK to cast to Binlog_file_reader here.
3680
3681 TODO: in the future investigate if some refactoring is needed
3682 here. Perhaps make the Iterator itself templated.
3683 */
3684
1/2
✓ Branch 0 taken 18014 times.
✗ Branch 1 not taken.
36028 binlog::tools::Iterator it(
3685 reinterpret_cast<Binlog_file_reader *>(&binlog_file_reader));
3686
3687 /*
3688 Unpacked events shall copy their part of the buffer from uncompressed
3689 buffer (the cointainer, i.e., the buffer iterator goes out of scope
3690 once the events are inflated and put in a vector). However, it is
3691 unclear if the *buffer* from which events are deserialized is still
3692 needed for the porposes of displaying events in SHOW BINLOG/RELAYLOG
3693 EVENTS.
3694 */
3695 36028 my_off_t last_log_pos = 0;
3696
4/6
✓ Branch 0 taken 18014 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 207215 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201246 times.
✓ Branch 5 taken 5969 times.
414430 for (event_count = 0, ev = it.begin(); ev != it.end();) {
3697
2/4
✓ Branch 0 taken 201246 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 201246 times.
✗ Branch 3 not taken.
402492 DEBUG_SYNC(thd, "wait_in_show_binlog_events_loop");
3698
3/4
✓ Branch 0 taken 200998 times.
✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 201246 times.
804488 if (event_count >= limit_start &&
3699
2/4
✓ Branch 0 taken 200998 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200998 times.
401996 ev->net_send(protocol, linfo.log_file_name, pos)) {
3700 /* purecov: begin inspected */
3701 errmsg = "Net error";
3702 delete ev;
3703 ev = nullptr;
3704 goto err;
3705 /* purecov: end */
3706 }
3707 402492 last_log_pos = ev->common_header->log_pos;
3708
1/2
✓ Branch 0 taken 201246 times.
✗ Branch 1 not taken.
402492 delete ev;
3709 402492 ev = nullptr;
3710 402492 pos = binlog_file_reader.position();
3711
3712
2/2
✓ Branch 0 taken 1499 times.
✓ Branch 1 taken 199747 times.
402492 if (++event_count == limit_end) break;
3713
4/6
✓ Branch 0 taken 199747 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 199747 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10545 times.
✓ Branch 5 taken 189202 times.
399494 if ((ev = it.next()) == it.end()) break;
3714
2/4
✓ Branch 0 taken 189202 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 189202 times.
378404 if (it.has_error()) break;
3715
4/4
✓ Branch 0 taken 187647 times.
✓ Branch 1 taken 1555 times.
✓ Branch 2 taken 187 times.
✓ Branch 3 taken 187460 times.
378404 if (end_pos > 0 && pos >= end_pos &&
3716
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 186 times.
374 (ev->common_header->log_pos != last_log_pos)) {
3717
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 delete ev;
3718 2 ev = nullptr;
3719 2 break;
3720 }
3721 }
3722
3723
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18013 times.
36028 if (binlog_file_reader.has_fatal_error())
3724
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 errmsg = binlog_file_reader.get_error_str();
3725
2/4
✓ Branch 0 taken 18013 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18013 times.
36026 else if (it.has_error())
3726 errmsg = it.get_error_message(); /* purecov: inspected */
3727 else
3728
1/2
✓ Branch 0 taken 18013 times.
✗ Branch 1 not taken.
36026 errmsg = "";
3729
3/4
✓ Branch 0 taken 18014 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18014 times.
✓ Branch 3 taken 17 times.
36062 }
3730 // Check that linfo is still on the function scope.
3731
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18020 times.
✓ Branch 2 taken 18020 times.
✗ Branch 3 not taken.
36040 DEBUG_SYNC(thd, "after_show_binlog_events");
3732
3733 err:
3734
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 18019 times.
36092 if (!errmsg.empty()) {
3735
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 25 times.
54 if (thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS)
3736
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SHOW RELAYLOG EVENTS",
3737 errmsg.c_str());
3738 else
3739
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
50 my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SHOW BINLOG EVENTS",
3740 errmsg.c_str());
3741 } else
3742
1/2
✓ Branch 0 taken 18019 times.
✗ Branch 1 not taken.
36038 my_eof(thd);
3743
3744
1/2
✓ Branch 0 taken 18046 times.
✗ Branch 1 not taken.
36092 mysql_mutex_lock(&thd->LOCK_thd_data);
3745 36092 thd->current_linfo = nullptr;
3746
1/2
✓ Branch 0 taken 18046 times.
✗ Branch 1 not taken.
36092 mysql_mutex_unlock(&thd->LOCK_thd_data);
3747 72184 return !errmsg.empty();
3748 36092 }
3749
3750 18046 bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log) {
3751
2/2
✓ Branch 0 taken 1253 times.
✓ Branch 1 taken 16793 times.
18046 if (binary_log->is_relay_log)
3752 1253 return show_binlog_events<Relaylog_file_reader>(thd, binary_log);
3753 16793 return show_binlog_events<Binlog_file_reader>(thd, binary_log);
3754 }
3755
3756 /**
3757 Execute a SHOW BINLOG EVENTS statement.
3758
3759 @param thd Pointer to THD object for the client thread executing the
3760 statement.
3761
3762 @retval false success
3763 @retval true failure
3764 */
3765 16793 bool mysql_show_binlog_events(THD *thd) {
3766
1/2
✓ Branch 0 taken 16793 times.
✗ Branch 1 not taken.
16793 DBUG_TRACE;
3767
3768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16793 times.
16793 assert(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS);
3769
3770 16793 mem_root_deque<Item *> field_list(thd->mem_root);
3771
1/2
✓ Branch 0 taken 16793 times.
✗ Branch 1 not taken.
16793 Log_event::init_show_field_list(&field_list);
3772
2/4
✓ Branch 0 taken 16793 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16793 times.
16793 if (thd->send_result_metadata(field_list,
3773 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
3774 return true;
3775
3776 /*
3777 Wait for handlers to insert any pending information
3778 into the binlog. For e.g. ndb which updates the binlog asynchronously
3779 this is needed so that the uses sees all its own commands in the binlog
3780 */
3781
1/2
✓ Branch 0 taken 16793 times.
✗ Branch 1 not taken.
16793 ha_binlog_wait(thd);
3782
3783
1/2
✓ Branch 0 taken 16793 times.
✗ Branch 1 not taken.
16793 return show_binlog_events(thd, &mysql_bin_log);
3784 16793 }
3785
3786 129882 MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period, bool relay_log)
3787 129882 : name(nullptr),
3788 129882 write_error(false),
3789 129882 inited(false),
3790
1/2
✓ Branch 0 taken 129883 times.
✗ Branch 1 not taken.
129882 m_binlog_file(new Binlog_ofile()),
3791 129882 m_key_LOCK_log(key_LOG_LOCK_log),
3792 129882 bytes_written(0),
3793 129882 binlog_space_total(0),
3794 129882 file_id(1),
3795 129882 sync_period_ptr(sync_period),
3796 129882 sync_counter(0),
3797 129882 is_relay_log(relay_log),
3798 129882 checksum_alg_reset(binary_log::BINLOG_CHECKSUM_ALG_UNDEF),
3799 129882 relay_log_checksum_alg(binary_log::BINLOG_CHECKSUM_ALG_UNDEF),
3800 129881 previous_gtid_set_relaylog(nullptr),
3801 129881 snapshot_lock_acquired(false),
3802
1/2
✓ Branch 0 taken 129882 times.
✗ Branch 1 not taken.
259764 is_rotating_caused_by_incident(false) {
3803 /*
3804 We don't want to initialize locks here as such initialization depends on
3805 safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
3806 called only in main(). Doing initialization here would make it happen
3807 before main().
3808 */
3809 129881 index_file_name[0] = 0;
3810 129881 }
3811
3812
2/2
✓ Branch 0 taken 98885 times.
✓ Branch 1 taken 26800 times.
251370 MYSQL_BIN_LOG::~MYSQL_BIN_LOG() { delete m_binlog_file; }
3813
3814 /* this is called only once */
3815
3816 26802 void MYSQL_BIN_LOG::cleanup() {
3817
1/2
✓ Branch 0 taken 26802 times.
✗ Branch 1 not taken.
26802 DBUG_TRACE;
3818
2/2
✓ Branch 0 taken 26800 times.
✓ Branch 1 taken 2 times.
26802 if (inited) {
3819 26800 inited = false;
3820
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT, true /*need_lock_log=true*/,
3821 true /*need_lock_index=true*/);
3822
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 mysql_mutex_destroy(&LOCK_log);
3823
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 mysql_mutex_destroy(&LOCK_index);
3824
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 mysql_mutex_destroy(&LOCK_commit);
3825
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 mysql_mutex_destroy(&LOCK_sync);
3826
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 mysql_mutex_destroy(&LOCK_binlog_end_pos);
3827
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 mysql_mutex_destroy(&LOCK_xids);
3828
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 mysql_cond_destroy(&update_cond);
3829
1/2
✓ Branch 0 taken 26800 times.
✗ Branch 1 not taken.
26800 mysql_cond_destroy(&m_prep_xids_cond);
3830
2/2
✓ Branch 0 taken 8468 times.
✓ Branch 1 taken 18332 times.
26800 if (!is_relay_log) {
3831
2/4
✓ Branch 0 taken 8468 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8468 times.
✗ Branch 3 not taken.
8468 Commit_stage_manager::get_instance().deinit();
3832 }
3833 }
3834
3835
2/2
✓ Branch 0 taken 26800 times.
✓ Branch 1 taken 2 times.
26802 delete m_binlog_file;
3836 26802 m_binlog_file = nullptr;
3837 26802 }
3838
3839 29501 void MYSQL_BIN_LOG::init_pthread_objects() {
3840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29501 times.
29501 assert(inited == 0);
3841 29501 inited = true;
3842
3843 29501 mysql_mutex_init(m_key_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
3844 29501 mysql_mutex_init(m_key_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW);
3845 29501 mysql_mutex_init(m_key_LOCK_commit, &LOCK_commit, MY_MUTEX_INIT_FAST);
3846 29501 mysql_mutex_init(m_key_LOCK_sync, &LOCK_sync, MY_MUTEX_INIT_FAST);
3847 29501 mysql_mutex_init(m_key_LOCK_binlog_end_pos, &LOCK_binlog_end_pos,
3848 MY_MUTEX_INIT_FAST);
3849 29501 mysql_mutex_init(m_key_LOCK_xids, &LOCK_xids, MY_MUTEX_INIT_FAST);
3850 29501 mysql_cond_init(m_key_update_cond, &update_cond);
3851 29501 mysql_cond_init(m_key_prep_xids_cond, &m_prep_xids_cond);
3852
2/2
✓ Branch 0 taken 9824 times.
✓ Branch 1 taken 19677 times.
29501 if (!is_relay_log) {
3853 9824 Commit_stage_manager::get_instance().init(
3854 m_key_LOCK_flush_queue, m_key_LOCK_sync_queue, m_key_LOCK_commit_queue,
3855 m_key_LOCK_done, m_key_COND_done, m_key_COND_flush_queue);
3856 }
3857 29501 }
3858
3859 /**
3860 Check if a string is a valid number.
3861
3862 @param str String to test
3863 @param res Store value here
3864 @param allow_wildcards Set to 1 if we should ignore '%' and '_'
3865
3866 @note
3867 For the moment the allow_wildcards argument is not used
3868 Should be moved to some other file.
3869
3870 @retval
3871 1 String is a number
3872 @retval
3873 0 String is not a number
3874 */
3875
3876 4546896 static bool is_number(const char *str, ulong *res, bool allow_wildcards) {
3877 int flag;
3878 const char *start;
3879
1/2
✓ Branch 0 taken 4546896 times.
✗ Branch 1 not taken.
4546896 DBUG_TRACE;
3880
3881 4546896 flag = 0;
3882 4546896 start = str;
3883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4546896 times.
4546896 while (*str++ == ' ')
3884 ;
3885
3/6
✓ Branch 0 taken 4546896 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4546896 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4546896 times.
4546896 if (*--str == '-' || *str == '+') str++;
3886
3/4
✓ Branch 0 taken 26242959 times.
✓ Branch 1 taken 4546896 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4546896 times.
30789855 while (my_isdigit(files_charset_info, *str) ||
3887 (allow_wildcards && (*str == wild_many || *str == wild_one))) {
3888 26242959 flag = 1;
3889 26242959 str++;
3890 }
3891
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4546886 times.
4546896 if (*str == '.') {
3892
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 for (str++; my_isdigit(files_charset_info, *str) ||
3893 (allow_wildcards && (*str == wild_many || *str == wild_one));
3894 str++, flag = 1)
3895 ;
3896 }
3897
3/4
✓ Branch 0 taken 4373803 times.
✓ Branch 1 taken 173093 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4373803 times.
4546896 if (*str != 0 || flag == 0) return false;
3898
1/2
✓ Branch 0 taken 4373804 times.
✗ Branch 1 not taken.
4373803 if (res) *res = atol(start);
3899 4373803 return true; /* Number ok */
3900 4546896 } /* is_number */
3901
3902 /**
3903 Find a unique filename for 'filename.#'.
3904
3905 Set '#' to the highest existing log file extension plus one.
3906
3907 This function will return nonzero if: (i) the generated name
3908 exceeds FN_REFLEN; (ii) if the number of extensions is exhausted;
3909 or (iii) some other error happened while examining the filesystem.
3910
3911 @return
3912 nonzero if not possible to get unique filename.
3913 */
3914
3915 125988 static int find_uniq_filename(char *name, uint32 new_index_number) {
3916 uint i;
3917 char buff[FN_REFLEN], ext_buf[FN_REFLEN];
3918 125988 MY_DIR *dir_info = nullptr;
3919 struct fileinfo *file_info;
3920 125988 ulong max_found = 0, next = 0, number = 0;
3921 size_t buf_length, length;
3922 char *start, *end;
3923 125988 int error = 0;
3924
1/2
✓ Branch 0 taken 125988 times.
✗ Branch 1 not taken.
125988 DBUG_TRACE;
3925
3926
1/2
✓ Branch 0 taken 125988 times.
✗ Branch 1 not taken.
125988 length = dirname_part(buff, name, &buf_length);
3927 125988 start = name + length;
3928 125988 end = strend(start);
3929
3930 125988 *end = '.';
3931 125988 length = (size_t)(end - start + 1);
3932
3933
7/10
✓ Branch 0 taken 125988 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 125975 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 125974 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 125974 times.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 125974 times.
125988 if ((DBUG_EVALUATE_IF(
3934 "error_unique_log_filename", 1,
3935 !(dir_info =
3936 my_dir(buff, MYF(MY_DONT_SORT)))))) { // This shouldn't happen
3937 13 my_stpcpy(end, ".1"); // use name+1
3938 13 return 1;
3939 }
3940 125974 file_info = dir_info->dir_entry;
3941
2/2
✓ Branch 0 taken 7369653 times.
✓ Branch 1 taken 125973 times.
7495626 for (i = dir_info->number_off_files; i--; file_info++) {
3942
4/4
✓ Branch 0 taken 4546895 times.
✓ Branch 1 taken 2822758 times.
✓ Branch 2 taken 4373801 times.
✓ Branch 3 taken 2995851 times.
11916547 if (strncmp(file_info->name, start, length) == 0 &&
3943
3/4
✓ Branch 0 taken 4546894 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4373801 times.
✓ Branch 3 taken 173093 times.
4546895 is_number(file_info->name + length, &number, false)) {
3944 4373801 max_found = std::max(max_found, number);
3945 }
3946 }
3947
1/2
✓ Branch 0 taken 125974 times.
✗ Branch 1 not taken.
125973 my_dirend(dir_info);
3948
3949 /* check if reached the maximum possible extension number */
3950
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 125969 times.
125974 if (max_found >= MAX_LOG_UNIQUE_FN_EXT) {
3951
8/16
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
5 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_EXTENSION_NUMBER_EXHAUSTED, max_found);
3952 5 error = 1;
3953 5 goto end;
3954 }
3955
3956
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 125957 times.
125969 if (new_index_number > 0) {
3957 /*
3958 If "new_index_number" was specified, this means we are handling a
3959 "RESET MASTER TO" command and the binary log was already purged
3960 so max_found should be 0.
3961 */
3962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(max_found == 0);
3963 12 next = new_index_number;
3964 } else
3965 125957 next = max_found + 1;
3966
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 125969 times.
125969 if (sprintf(ext_buf, "%06lu", next) < 0) {
3967 error = 1;
3968 goto end;
3969 }
3970 125969 *end++ = '.';
3971
3972 /*
3973 Check if the generated extension size + the file name exceeds the
3974 buffer size used. If one did not check this, then the filename might be
3975 truncated, resulting in error.
3976 */
3977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 125969 times.
125969 if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN)) {
3978 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_NAME_TOO_LONG, name, ext_buf,
3979 (strlen(ext_buf) + (end - name)));
3980 error = 1;
3981 goto end;
3982 }
3983
3984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 125969 times.
125969 if (sprintf(end, "%06lu", next) < 0) {
3985 error = 1;
3986 goto end;
3987 }
3988
3989 /* print warning if reaching the end of available extensions. */
3990
2/2
✓ Branch 0 taken 125961 times.
✓ Branch 1 taken 8 times.
125969 if (next > MAX_ALLOWED_FN_EXT_RESET_MASTER)
3991
8/16
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 8 times.
✗ Branch 15 not taken.
8 LogErr(WARNING_LEVEL, ER_BINLOG_FILE_EXTENSION_NUMBER_RUNNING_LOW, next,
3992 (MAX_LOG_UNIQUE_FN_EXT - next));
3993
3994 125961 end:
3995 125974 return error;
3996 125987 }
3997
3998 125988 int MYSQL_BIN_LOG::generate_new_name(char *new_name, const char *log_name,
3999 uint32 new_index_number) {
4000 125988 fn_format(new_name, log_name, mysql_data_home, "", 4);
4001
1/2
✓ Branch 0 taken 125988 times.
✗ Branch 1 not taken.
125988 if (!fn_ext(log_name)[0]) {
4002
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 125968 times.
125988 if (find_uniq_filename(new_name, new_index_number)) {
4003
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
19 if (current_thd != nullptr)
4004 16 my_printf_error(ER_NO_UNIQUE_LOGFILE,
4005 16 ER_THD(current_thd, ER_NO_UNIQUE_LOGFILE),
4006 MYF(ME_FATALERROR), log_name);
4007
7/14
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 18 times.
✗ Branch 13 not taken.
18 LogErr(ERROR_LEVEL, ER_FAILED_TO_GENERATE_UNIQUE_LOGFILE, log_name);
4008 18 return 1;
4009 }
4010 }
4011 125968 return 0;
4012 }
4013
4014 /**
4015 @todo
4016 The following should be using fn_format(); We just need to
4017 first change fn_format() to cut the file name if it's too long.
4018 */
4019 21088 const char *MYSQL_BIN_LOG::generate_name(const char *log_name,
4020 const char *suffix, char *buff) {
4021
3/4
✓ Branch 0 taken 16127 times.
✓ Branch 1 taken 4961 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16127 times.
21088 if (!log_name || !log_name[0]) {
4022
3/4
✓ Branch 0 taken 4961 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 4915 times.
4961 if (is_relay_log || log_bin_supplied)
4023 46 strmake(buff, default_logfile_name, FN_REFLEN - strlen(suffix) - 1);
4024 else
4025 4915 strmake(buff, default_binlogfile_name, FN_REFLEN - strlen(suffix) - 1);
4026
4027 4961 return (const char *)fn_format(buff, buff, "", suffix,
4028 4961 MYF(MY_REPLACE_EXT | MY_REPLACE_DIR));
4029 }
4030 // get rid of extension to avoid problems
4031
4032 16127 const char *p = fn_ext(log_name);
4033 16127 uint length = (uint)(p - log_name);
4034
1/2
✓ Branch 0 taken 16127 times.
✗ Branch 1 not taken.
16127 strmake(buff, log_name, min<size_t>(length, FN_REFLEN - 1));
4035 16127 return (const char *)buff;
4036 }
4037
4038 157725 bool MYSQL_BIN_LOG::init_and_set_log_file_name(const char *log_name,
4039 const char *new_name,
4040 uint32 new_index_number) {
4041
4/6
✓ Branch 0 taken 63524 times.
✓ Branch 1 taken 94201 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63524 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 157725 times.
157725 if (new_name && !my_stpcpy(log_file_name, new_name))
4042 return true;
4043
4/4
✓ Branch 0 taken 94202 times.
✓ Branch 1 taken 63523 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 157721 times.
251926 else if (!new_name &&
4044
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 94198 times.
94202 generate_new_name(log_file_name, log_name, new_index_number))
4045 3 return true;
4046
4047 157721 return false;
4048 }
4049
4050 /**
4051 Open the logfile and init IO_CACHE.
4052
4053 @param log_file_key The file instrumentation key for this file
4054 @param log_name The name of the log to open
4055 @param new_name The new name for the logfile.
4056 NULL forces generate_new_name() to be called.
4057 @param new_index_number The binary log file index number to start from
4058 after the RESET MASTER TO command is called.
4059
4060 @return true if error, false otherwise.
4061 */
4062
4063 78860 bool MYSQL_BIN_LOG::open(PSI_file_key log_file_key, const char *log_name,
4064 const char *new_name, uint32 new_index_number) {
4065
1/2
✓ Branch 0 taken 78860 times.
✗ Branch 1 not taken.
78860 DBUG_TRACE;
4066 78860 bool ret = false;
4067
4068 78860 write_error = false;
4069 78860 myf flags = MY_WME | MY_NABP | MY_WAIT_IF_FULL;
4070
2/2
✓ Branch 0 taken 52759 times.
✓ Branch 1 taken 26101 times.
78860 if (is_relay_log) flags = flags | MY_REPORT_WAITING_IF_FULL;
4071
4072
2/4
✓ Branch 0 taken 78860 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78860 times.
78860 if (!(name = my_strdup(key_memory_MYSQL_LOG_name, log_name, MYF(MY_WME)))) {
4073 goto err;
4074 }
4075
4076
4/6
✓ Branch 0 taken 78859 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78859 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 78858 times.
157719 if (init_and_set_log_file_name(name, new_name, new_index_number) ||
4077
3/4
✓ Branch 0 taken 78859 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 78858 times.
78859 DBUG_EVALUATE_IF("fault_injection_init_name", 1, 0))
4078 1 goto err;
4079
4080 78858 db[0] = 0;
4081
4082 /* Keep the key for reopen */
4083 78858 m_log_file_key = log_file_key;
4084
4085 /*
4086 LOCK_sync guarantees that no thread is calling m_binlog_file to sync data
4087 to disk when another thread is opening the new file
4088 (FLUSH LOG or RESET MASTER).
4089 */
4090
3/4
✓ Branch 0 taken 26099 times.
✓ Branch 1 taken 52759 times.
✓ Branch 2 taken 26099 times.
✗ Branch 3 not taken.
78858 if (!is_relay_log) mysql_mutex_lock(&LOCK_sync);
4091
4092
1/2
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
78858 ret = m_binlog_file->open(log_file_key, log_file_name, flags);
4093
4094
3/4
✓ Branch 0 taken 26099 times.
✓ Branch 1 taken 52759 times.
✓ Branch 2 taken 26099 times.
✗ Branch 3 not taken.
78858 if (!is_relay_log) mysql_mutex_unlock(&LOCK_sync);
4095
4096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78858 times.
78858 if (ret) goto err;
4097
4098 78858 atomic_log_state = LOG_OPENED;
4099 78858 return false;
4100
4101 1 err:
4102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (binlog_error_action == ABORT_SERVER) {
4103 exec_binlog_error_action_abort(
4104 "Either disk is full, file system is read only or "
4105 "there was an encryption error while opening the binlog. "
4106 "Aborting the server.");
4107 } else
4108
8/16
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_FOR_LOGGING, log_name, errno);
4109
4110
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_free(name);
4111 1 name = nullptr;
4112 1 atomic_log_state = LOG_CLOSED;
4113 1 return true;
4114 78859 }
4115
4116 79082 bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
4117 const char *log_name,
4118 bool need_lock_index) {
4119 79082 bool error = false;
4120 79082 File index_file_nr = -1;
4121
2/2
✓ Branch 0 taken 21051 times.
✓ Branch 1 taken 58031 times.
79082 if (need_lock_index)
4122 21051 mysql_mutex_lock(&LOCK_index);
4123 else
4124 mysql_mutex_assert_owner(&LOCK_index);
4125
4126 /*
4127 First open of this class instance
4128 Create an index file that will hold all file names uses for logging.
4129 Add new entries to the end of it.
4130 */
4131 79082 myf opt = MY_UNPACK_FILENAME;
4132
4133
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 79081 times.
79082 if (my_b_inited(&index_file)) goto end;
4134
4135
2/2
✓ Branch 0 taken 21029 times.
✓ Branch 1 taken 58052 times.
79081 if (!index_file_name_arg) {
4136 21029 index_file_name_arg = log_name; // Use same basename for index file
4137 21029 opt = MY_UNPACK_FILENAME | MY_REPLACE_EXT;
4138 }
4139 79081 fn_format(index_file_name, index_file_name_arg, mysql_data_home, ".index",
4140 opt);
4141
4142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79081 times.
79081 if (set_crash_safe_index_file_name(index_file_name_arg)) {
4143 error = true;
4144 goto end;
4145 }
4146
4147 /*
4148 We need move crash_safe_index_file to index_file if the index_file
4149 does not exist and crash_safe_index_file exists when mysqld server
4150 restarts.
4151 */
4152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35676 times.
114757 if (my_access(index_file_name, F_OK) &&
4153
3/4
✓ Branch 0 taken 35676 times.
✓ Branch 1 taken 43405 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 79081 times.
114757 !my_access(crash_safe_index_file_name, F_OK) &&
4154 my_rename(crash_safe_index_file_name, index_file_name, MYF(MY_WME))) {
4155 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_MOVE_TMP_TO_INDEX,
4156 "MYSQL_BIN_LOG::open_index_file");
4157 error = true;
4158 goto end;
4159 }
4160
4161 79081 if ((index_file_nr = mysql_file_open(m_key_file_log_index, index_file_name,
4162 79080 O_RDWR | O_CREAT, MYF(MY_WME))) < 0 ||
4163
1/2
✓ Branch 0 taken 79080 times.
✗ Branch 1 not taken.
79080 mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
4164
1/2
✓ Branch 0 taken 79080 times.
✗ Branch 1 not taken.
79080 init_io_cache_ext(&index_file, index_file_nr, IO_SIZE, READ_CACHE,
4165 mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
4166 false, MYF(MY_WME | MY_WAIT_IF_FULL),
4167
4/4
✓ Branch 0 taken 79080 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 79078 times.
158161 m_key_file_log_index_cache) ||
4168
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 79078 times.
79080 DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0)) {
4169 /*
4170 TODO: all operations creating/deleting the index file or a log, should
4171 call my_sync_dir() or my_sync_dir_by_file() to be durable.
4172 TODO: file creation should be done with mysql_file_create()
4173 not mysql_file_open().
4174 */
4175
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (index_file_nr >= 0) mysql_file_close(index_file_nr, MYF(0));
4176 3 error = true;
4177 3 goto end;
4178 }
4179
4180 /*
4181 Sync the index by purging any binary log file that is not registered.
4182 In other words, either purge binary log files that were removed from
4183 the index but not purged from the file system due to a crash or purge
4184 any binary log file that was created but not register in the index
4185 due to a crash.
4186 */
4187
4188 79078 if (set_purge_index_file_name(index_file_name_arg) ||
4189
1/2
✓ Branch 0 taken 79078 times.
✗ Branch 1 not taken.
79078 open_purge_index_file(false) ||
4190
4/8
✓ Branch 0 taken 79078 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 79078 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 79078 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 79078 times.
✗ Branch 7 not taken.
237234 purge_index_entry(nullptr, nullptr, false) || close_purge_index_file() ||
4191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79078 times.
79078 DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0)) {
4192 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_SYNC_INDEX_FILE);
4193 error = true;
4194 goto end;
4195 }
4196
4197 79078 end:
4198
2/2
✓ Branch 0 taken 21051 times.
✓ Branch 1 taken 58031 times.
79082 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
4199 79082 return error;
4200 }
4201
4202 /**
4203 Add the GTIDs from the given relaylog file and also
4204 update the IO thread transaction parser.
4205
4206 @param filename Relaylog file to read from.
4207 @param retrieved_gtids Gtid_set to store the GTIDs found on the relaylog file.
4208 @param verify_checksum Set to true to verify event checksums.
4209 @param trx_parser The transaction boundary parser to be used in order to
4210 only add a GTID to the gtid_set after ensuring the transaction is fully
4211 stored on the relay log.
4212 @param partial_trx The trx_monitoring_info of the last incomplete transaction
4213 found in the relay log.
4214
4215 @retval false The file was successfully read and all GTIDs from
4216 Previous_gtids and Gtid_log_event from complete transactions were added to
4217 the retrieved_set.
4218 @retval true There was an error during the procedure.
4219 */
4220 9668 static bool read_gtids_and_update_trx_parser_from_relaylog(
4221 const char *filename, Gtid_set *retrieved_gtids, bool verify_checksum,
4222 Transaction_boundary_parser *trx_parser,
4223 Gtid_monitoring_info *partial_trx) {
4224
1/2
✓ Branch 0 taken 9668 times.
✗ Branch 1 not taken.
9668 DBUG_TRACE;
4225
3/8
✓ Branch 0 taken 9668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9668 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9668 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9668 DBUG_PRINT("info", ("Opening file %s", filename));
4226
4227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9668 times.
9668 assert(retrieved_gtids != nullptr);
4228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9668 times.
9668 assert(trx_parser != nullptr);
4229 #ifndef NDEBUG
4230 9668 unsigned long event_counter = 0;
4231 #endif
4232 9668 bool error = false;
4233
4234
1/2
✓ Branch 0 taken 9668 times.
✗ Branch 1 not taken.
9668 Relaylog_file_reader relaylog_file_reader(verify_checksum);
4235
3/4
✓ Branch 0 taken 9668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 9662 times.
9668 if (relaylog_file_reader.open(filename)) {
4236
9/18
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
6 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_OPEN_FAILED,
4237 relaylog_file_reader.get_error_str());
4238
4239 /*
4240 As read_gtids_from_binlog() will not throw error on truncated
4241 relaylog files, we should do the same here in order to keep the
4242 current behavior.
4243 */
4244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (relaylog_file_reader.get_error_type() ==
4245 Binlog_read_error::CANNOT_GET_FILE_PASSWORD)
4246 error = true;
4247 6 return error;
4248 }
4249
4250 9662 Log_event *ev = nullptr;
4251 9662 bool seen_prev_gtids = false;
4252 9662 ulong data_len = 0;
4253
4254
6/8
✓ Branch 0 taken 42939 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42939 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33277 times.
✓ Branch 5 taken 9662 times.
✓ Branch 6 taken 33277 times.
✓ Branch 7 taken 9662 times.
42939 while (!error && (ev = relaylog_file_reader.read_event_object()) != nullptr) {
4255
3/10
✓ Branch 0 taken 33277 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33277 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33277 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
33277 DBUG_PRINT("info", ("Read event of type %s", ev->get_type_str()));
4256 #ifndef NDEBUG
4257 33277 event_counter++;
4258 #endif
4259
4260 33277 data_len = uint4korr(ev->temp_buf + EVENT_LEN_OFFSET);
4261
4262 33277 bool info_error{false};
4263 33277 binary_log::Log_event_basic_info log_event_info;
4264 66554 std::tie(info_error, log_event_info) = extract_log_event_basic_info(
4265
1/2
✓ Branch 0 taken 33277 times.
✗ Branch 1 not taken.
33277 ev->temp_buf, data_len,
4266 33277 relaylog_file_reader.format_description_event());
4267
4268
6/8
✓ Branch 0 taken 33277 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33277 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 33274 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 33274 times.
33277 if (info_error || trx_parser->feed_event(log_event_info, false)) {
4269 /*
4270 The transaction boundary parser found an error while parsing a
4271 sequence of events from the relaylog. As we don't know if the
4272 parsing has started from a reliable point (it might started in
4273 a relay log file that begins with the rest of a transaction
4274 that started in a previous relay log file), it is better to do
4275 nothing in this case. The boundary parser will fix itself once
4276 finding an event that represent a transaction boundary.
4277
4278 Suppose the following relaylog:
4279
4280 rl-bin.000011 | rl-bin.000012 | rl-bin.000013 | rl-bin-000014
4281 ---------------+---------------+---------------+---------------
4282 PREV_GTIDS | PREV_GTIDS | PREV_GTIDS | PREV_GTIDS
4283 (empty) | (UUID:1-2) | (UUID:1-2) | (UUID:1-2)
4284 ---------------+---------------+---------------+---------------
4285 XID | QUERY(INSERT) | QUERY(INSERT) | XID
4286 ---------------+---------------+---------------+---------------
4287 GTID(UUID:2) |
4288 ---------------+
4289 QUERY(CREATE |
4290 TABLE t1 ...) |
4291 ---------------+
4292 GTID(UUID:3) |
4293 ---------------+
4294 QUERY(BEGIN) |
4295 ---------------+
4296
4297 As it is impossible to determine the current Retrieved_Gtid_Set by only
4298 looking to the PREVIOUS_GTIDS on the last relay log file, and scanning
4299 events on it, we tried to find a relay log file that contains at least
4300 one GTID event during the backwards search.
4301
4302 In the example, we will find a GTID only in rl-bin.000011, as the
4303 UUID:3 transaction was spanned across 4 relay log files.
4304
4305 The transaction spanning can be caused by "FLUSH RELAY LOGS" commands
4306 on slave while it is queuing the transaction.
4307
4308 So, in order to correctly add UUID:3 into Retrieved_Gtid_Set, we need
4309 to parse the relay log starting on the file we found the last GTID
4310 queued to know if the transaction was fully retrieved or not.
4311
4312 Start scanning rl-bin.000011 after resetting the transaction parser
4313 will generate an error, as XID event is only expected inside a DML,
4314 but in this case, we can ignore this error and reset the parser.
4315 */
4316
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 trx_parser->reset();
4317 /*
4318 We also have to discard the GTID of the partial transaction that was
4319 not finished if there is one. This is needed supposing that an
4320 incomplete transaction was replicated with a GTID.
4321
4322 GTID(1), QUERY(BEGIN), QUERY(INSERT), ANONYMOUS_GTID, QUERY(DROP ...)
4323
4324 In the example above, without cleaning the partial_trx,
4325 the GTID(1) would be added to the Retrieved_Gtid_Set after the
4326 QUERY(DROP ...) event.
4327
4328 GTID(1), QUERY(BEGIN), QUERY(INSERT), GTID(2), QUERY(DROP ...)
4329
4330 In the example above the GTID(1) will also be discarded as the
4331 GTID(1) transaction is not complete.
4332 */
4333
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (partial_trx->is_processing_trx_set()) {
4334 DBUG_PRINT("info",
4335 ("Discarding Gtid(%d, %" PRId64 ") as the transaction "
4336 "wasn't complete and we found an error in the"
4337 "transaction boundary parser.",
4338 partial_trx->get_processing_trx_gtid()->sidno,
4339 partial_trx->get_processing_trx_gtid()->gno));
4340 partial_trx->clear_processing_trx();
4341 }
4342 }
4343
4344
4/4
✓ Branch 0 taken 11765 times.
✓ Branch 1 taken 9662 times.
✓ Branch 2 taken 1811 times.
✓ Branch 3 taken 10039 times.
33277 switch (ev->get_type_code()) {
4345 11765 case binary_log::FORMAT_DESCRIPTION_EVENT:
4346 case binary_log::ROTATE_EVENT:
4347 // do nothing; just accept this event and go to next
4348 11765 break;
4349 9662 case binary_log::PREVIOUS_GTIDS_LOG_EVENT: {
4350 9662 seen_prev_gtids = true;
4351 // add events to sets
4352 9662 Previous_gtids_log_event *prev_gtids_ev =
4353
1/2
✓ Branch 0 taken 9662 times.
✗ Branch 1 not taken.
9662 (Previous_gtids_log_event *)ev;
4354
2/4
✓ Branch 0 taken 9662 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9662 times.
9662 if (prev_gtids_ev->add_to_set(retrieved_gtids) != 0) {
4355 error = true;
4356 break;
4357 }
4358 #ifndef NDEBUG
4359
1/2
✓ Branch 0 taken 9662 times.
✗ Branch 1 not taken.
9662 char *prev_buffer = prev_gtids_ev->get_str(nullptr, nullptr);
4360
3/8
✓ Branch 0 taken 9662 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9662 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9662 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9662 DBUG_PRINT("info", ("Got Previous_gtids from file '%s': Gtid_set='%s'.",
4361 filename, prev_buffer));
4362
1/2
✓ Branch 0 taken 9662 times.
✗ Branch 1 not taken.
9662 my_free(prev_buffer);
4363 #endif
4364 9662 break;
4365 }
4366 1811 case binary_log::GTID_LOG_EVENT: {
4367 /* If we didn't find any PREVIOUS_GTIDS in this file */
4368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1811 times.
1811 if (!seen_prev_gtids) {
4369 my_error(ER_BINLOG_LOGICAL_CORRUPTION, MYF(0), filename,
4370 "The first global transaction identifier was read, but "
4371 "no other information regarding identifiers existing "
4372 "on the previous log files was found.");
4373 error = true;
4374 break;
4375 }
4376
4377
1/2
✓ Branch 0 taken 1811 times.
✗ Branch 1 not taken.
1811 Gtid_log_event *gtid_ev = (Gtid_log_event *)ev;
4378
1/2
✓ Branch 0 taken 1811 times.
✗ Branch 1 not taken.
1811 rpl_sidno sidno = gtid_ev->get_sidno(retrieved_gtids->get_sid_map());
4379 1811 ulonglong immediate_commit_timestamp =
4380 gtid_ev->immediate_commit_timestamp;
4381 1811 longlong original_commit_timestamp = gtid_ev->original_commit_timestamp;
4382
4383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1811 times.
1811 if (sidno < 0) {
4384 error = true;
4385 break;
4386 } else {
4387
2/4
✓ Branch 0 taken 1811 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1811 times.
1811 if (retrieved_gtids->ensure_sidno(sidno) != RETURN_STATUS_OK) {
4388 error = true;
4389 break;
4390 } else {
4391 1811 Gtid gtid = {sidno, gtid_ev->get_gno()};
4392 /*
4393 As are updating the transaction boundary parser while reading
4394 GTIDs from relay log files to fill the Retrieved_Gtid_Set, we
4395 should not add the GTID here as we don't know if the transaction
4396 is complete on the relay log yet.
4397 */
4398
1/2
✓ Branch 0 taken 1811 times.
✗ Branch 1 not taken.
1811 partial_trx->start(gtid, original_commit_timestamp,
4399 immediate_commit_timestamp);
4400 }
4401
3/8
✓ Branch 0 taken 1811 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1811 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1811 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1811 DBUG_PRINT(
4402 "info",
4403 ("Found Gtid in relaylog file '%s': Gtid(%d, %" PRId64 ").",
4404 filename, sidno, gtid_ev->get_gno()));
4405 }
4406 1811 break;
4407 }
4408 10039 case binary_log::ANONYMOUS_GTID_LOG_EVENT:
4409 default:
4410 /*
4411 If we reached the end of a transaction after storing it's GTID
4412 in partial_trx structure, it is time to add this GTID to the
4413 retrieved_gtids set because the transaction is complete and there is
4414 no need for asking this transaction again.
4415 */
4416
2/2
✓ Branch 0 taken 3645 times.
✓ Branch 1 taken 6394 times.
10039 if (trx_parser->is_not_inside_transaction()) {
4417
3/4
✓ Branch 0 taken 3645 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1809 times.
✓ Branch 3 taken 1836 times.
3645 if (partial_trx->is_processing_trx_set()) {
4418 const Gtid *fully_retrieved_gtid;
4419
1/2
✓ Branch 0 taken 1809 times.
✗ Branch 1 not taken.
1809 fully_retrieved_gtid = partial_trx->get_processing_trx_gtid();
4420
3/8
✓ Branch 0 taken 1809 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1809 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1809 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1809 DBUG_PRINT("info", ("Adding Gtid to Retrieved_Gtid_Set as the "
4421 "transaction was completed at "
4422 "relaylog file '%s': Gtid(%d, %" PRId64 ").",
4423 filename, fully_retrieved_gtid->sidno,
4424 fully_retrieved_gtid->gno));
4425
1/2
✓ Branch 0 taken 1809 times.
✗ Branch 1 not taken.
1809 retrieved_gtids->_add_gtid(*fully_retrieved_gtid);
4426 /*
4427 We don't need to update the last queued structure here. We just
4428 want to have the information about the partial transaction left in
4429 the relay log.
4430 */
4431
1/2
✓ Branch 0 taken 1809 times.
✗ Branch 1 not taken.
1809 partial_trx->clear();
4432 }
4433 }
4434 10039 break;
4435 }
4436
1/2
✓ Branch 0 taken 33277 times.
✗ Branch 1 not taken.
33277 delete ev;
4437 }
4438
4439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9662 times.
9662 if (relaylog_file_reader.has_fatal_error()) {
4440 // This is not a fatal error; the log may just be truncated.
4441 // @todo but what other errors could happen? IO error?
4442 LogErr(WARNING_LEVEL, ER_BINLOG_ERROR_READING_GTIDS_FROM_RELAY_LOG, -1);
4443 sql_print_warning(relaylog_file_reader.get_error_str());
4444 }
4445
4446 #ifndef NDEBUG
4447
8/16
✓ Branch 0 taken 9662 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9662 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9662 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9662 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9662 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9662 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9662 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9662 times.
✗ Branch 15 not taken.
9662 LogErr(INFORMATION_LEVEL, ER_BINLOG_EVENTS_READ_FROM_RELAY_LOG_INFO,
4448 event_counter, filename);
4449 #endif
4450
4451 9662 return error;
4452 9668 }
4453
4454 enum enum_read_gtids_from_binlog_status {
4455 GOT_GTIDS,
4456 GOT_PREVIOUS_GTIDS,
4457 NO_GTIDS,
4458 ERROR,
4459 TRUNCATED
4460 };
4461 /**
4462 Reads GTIDs from the given binlog file.
4463
4464 @param filename File to read from.
4465 @param all_gtids If not NULL, then the GTIDs from the
4466 Previous_gtids_log_event and from all Gtid_log_events are stored in
4467 this object.
4468 @param prev_gtids If not NULL, then the GTIDs from the
4469 Previous_gtids_log_events are stored in this object.
4470 @param first_gtid If not NULL, then the first GTID information from the
4471 file will be stored in this object.
4472 @param sid_map The sid_map object to use in the rpl_sidno generation
4473 of the Gtid_log_event. If lock is needed in the sid_map, the caller
4474 must hold it.
4475 @param verify_checksum Set to true to verify event checksums.
4476 @param is_relay_log Set to true, if filename is a Relay Log, false if it is a
4477 Binary Log.
4478 @retval GOT_GTIDS The file was successfully read and it contains
4479 both Gtid_log_events and Previous_gtids_log_events.
4480 This is only possible if either all_gtids or first_gtid are not null.
4481 @retval GOT_PREVIOUS_GTIDS The file was successfully read and it
4482 contains Previous_gtids_log_events but no Gtid_log_events.
4483 For binary logs, if no all_gtids and no first_gtid are specified,
4484 this function will be done right after reading the PREVIOUS_GTIDS
4485 regardless of the rest of the content of the binary log file.
4486 @retval NO_GTIDS The file was successfully read and it does not
4487 contain GTID events.
4488 @retval ERROR Out of memory, or IO error, or malformed event
4489 structure, or the file is malformed (e.g., contains Gtid_log_events
4490 but no Previous_gtids_log_event).
4491 @retval TRUNCATED The file was truncated before the end of the
4492 first Previous_gtids_log_event.
4493 */
4494 20625 static enum_read_gtids_from_binlog_status read_gtids_from_binlog(
4495 const char *filename, Gtid_set *all_gtids, Gtid_set *prev_gtids,
4496 Gtid *first_gtid, Sid_map *sid_map, bool verify_checksum,
4497 bool is_relay_log) {
4498
1/2
✓ Branch 0 taken 20625 times.
✗ Branch 1 not taken.
20625 DBUG_TRACE;
4499
3/8
✓ Branch 0 taken 20625 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20625 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20625 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20625 DBUG_PRINT("info", ("Opening file %s", filename));
4500
4501 #ifndef NDEBUG
4502 20625 unsigned long event_counter = 0;
4503 /*
4504 We assert here that both all_gtids and prev_gtids, if specified,
4505 uses the same sid_map as the one passed as a parameter. This is just
4506 to ensure that, if the sid_map needed some lock and was locked by
4507 the caller, the lock applies to all the GTID sets this function is
4508 dealing with.
4509 */
4510
3/4
✓ Branch 0 taken 14497 times.
✓ Branch 1 taken 6128 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14497 times.
20625 if (all_gtids) assert(all_gtids->get_sid_map() == sid_map);
4511
3/4
✓ Branch 0 taken 7471 times.
✓ Branch 1 taken 13154 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7471 times.
20625 if (prev_gtids) assert(prev_gtids->get_sid_map() == sid_map);
4512 #endif
4513
4514
1/2
✓ Branch 0 taken 20625 times.
✗ Branch 1 not taken.
20625 Binlog_file_reader binlog_file_reader(verify_checksum);
4515
3/4
✓ Branch 0 taken 20625 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 20618 times.
20625 if (binlog_file_reader.open(filename)) {
4516
9/18
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 17 not taken.
7 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_OPEN_FAILED,
4517 binlog_file_reader.get_error_str());
4518 /*
4519 We need to revisit the recovery procedure for relay log
4520 files. Currently, it is called after this routine.
4521 /Alfranio
4522 */
4523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (binlog_file_reader.get_error_type() ==
4524 Binlog_read_error::CANNOT_GET_FILE_PASSWORD)
4525 return ERROR;
4526 7 return TRUNCATED;
4527 }
4528
4529 20618 Log_event *ev = nullptr;
4530 20618 enum_read_gtids_from_binlog_status ret = NO_GTIDS;
4531 20618 bool done = false;
4532 20618 bool seen_first_gtid = false;
4533
7/8
✓ Branch 0 taken 8910635 times.
✓ Branch 1 taken 6708 times.
✓ Branch 2 taken 8910635 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8896725 times.
✓ Branch 5 taken 13910 times.
✓ Branch 6 taken 8896725 times.
✓ Branch 7 taken 20618 times.
8917343 while (!done && (ev = binlog_file_reader.read_event_object()) != nullptr) {
4534 #ifndef NDEBUG
4535 8896725 event_counter++;
4536 #endif
4537
3/10
✓ Branch 0 taken 8896725 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8896725 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8896725 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
8896725 DBUG_PRINT("info", ("Read event of type %s", ev->get_type_str()));
4538
5/5
✓ Branch 0 taken 22776 times.
✓ Branch 1 taken 20564 times.
✓ Branch 2 taken 6818 times.
✓ Branch 3 taken 853332 times.
✓ Branch 4 taken 7993235 times.
8896725 switch (ev->get_type_code()) {
4539 22776 case binary_log::FORMAT_DESCRIPTION_EVENT:
4540 case binary_log::ROTATE_EVENT:
4541 // do nothing; just accept this event and go to next
4542 22776 break;
4543 20564 case binary_log::PREVIOUS_GTIDS_LOG_EVENT: {
4544 20564 ret = GOT_PREVIOUS_GTIDS;
4545 // add events to sets
4546 20564 Previous_gtids_log_event *prev_gtids_ev =
4547
1/2
✓ Branch 0 taken 20564 times.
✗ Branch 1 not taken.
20564 (Previous_gtids_log_event *)ev;
4548
5/8
✓ Branch 0 taken 14454 times.
✓ Branch 1 taken 6110 times.
✓ Branch 2 taken 14454 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14454 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 20564 times.
20564 if (all_gtids != nullptr && prev_gtids_ev->add_to_set(all_gtids) != 0)
4549 ret = ERROR, done = true;
4550
3/4
✓ Branch 0 taken 7453 times.
✓ Branch 1 taken 13111 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20564 times.
28017 else if (prev_gtids != nullptr &&
4551
2/4
✓ Branch 0 taken 7453 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7453 times.
7453 prev_gtids_ev->add_to_set(prev_gtids) != 0)
4552 ret = ERROR, done = true;
4553 #ifndef NDEBUG
4554
1/2
✓ Branch 0 taken 20564 times.
✗ Branch 1 not taken.
20564 char *prev_buffer = prev_gtids_ev->get_str(nullptr, nullptr);
4555
3/8
✓ Branch 0 taken 20564 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20564 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20564 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20564 DBUG_PRINT("info", ("Got Previous_gtids from file '%s': Gtid_set='%s'.",
4556 filename, prev_buffer));
4557
1/2
✓ Branch 0 taken 20564 times.
✗ Branch 1 not taken.
20564 my_free(prev_buffer);
4558 #endif
4559 /*
4560 If this is not a relay log, the previous_gtids were asked and no
4561 all_gtids neither first_gtid were asked, it is fine to consider the
4562 job as done.
4563 */
4564
8/8
✓ Branch 0 taken 10904 times.
✓ Branch 1 taken 9660 times.
✓ Branch 2 taken 7453 times.
✓ Branch 3 taken 3451 times.
✓ Branch 4 taken 6110 times.
✓ Branch 5 taken 1343 times.
✓ Branch 6 taken 3515 times.
✓ Branch 7 taken 2595 times.
20564 if (!is_relay_log && prev_gtids != nullptr && all_gtids == nullptr &&
4565 first_gtid == nullptr)
4566 3515 done = true;
4567
2/14
✓ Branch 0 taken 20564 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20564 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
20564 DBUG_EXECUTE_IF("inject_fault_bug16502579", {
4568 DBUG_PRINT("debug", ("PREVIOUS_GTIDS_LOG_EVENT found. "
4569 "Injected ret=NO_GTIDS."));
4570 if (ret == GOT_PREVIOUS_GTIDS) {
4571 ret = NO_GTIDS;
4572 done = false;
4573 }
4574 });
4575 20564 break;
4576 }
4577 6818 case binary_log::GTID_LOG_EVENT: {
4578
2/2
✓ Branch 0 taken 2438 times.
✓ Branch 1 taken 4380 times.
6818 if (ret != GOT_GTIDS) {
4579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2438 times.
2438 if (ret != GOT_PREVIOUS_GTIDS) {
4580 /*
4581 Since this routine is run on startup, there may not be a
4582 THD instance. Therefore, ER(X) cannot be used.
4583 */
4584 const char *msg_fmt =
4585 (current_thd != nullptr)
4586 ? ER_THD(current_thd, ER_BINLOG_LOGICAL_CORRUPTION)
4587 : ER_DEFAULT(ER_BINLOG_LOGICAL_CORRUPTION);
4588 my_printf_error(
4589 ER_BINLOG_LOGICAL_CORRUPTION, msg_fmt, MYF(0), filename,
4590 "The first global transaction identifier was read, but "
4591 "no other information regarding identifiers existing "
4592 "on the previous log files was found.");
4593 ret = ERROR, done = true;
4594 break;
4595 } else
4596 2438 ret = GOT_GTIDS;
4597 }
4598 /*
4599 When this is a relaylog, we just check if the relay log contains at
4600 least one Gtid_log_event, so that we can distinguish the return values
4601 GOT_GTID and GOT_PREVIOUS_GTIDS. We don't need to read anything else
4602 from the relay log.
4603 When this is a binary log, if all_gtids is requested (i.e., NOT NULL),
4604 we should continue to read all gtids. If just first_gtid was
4605 requested, we will be done after storing this Gtid_log_event info on
4606 it.
4607 */
4608
2/2
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 6546 times.
6818 if (is_relay_log) {
4609 272 ret = GOT_GTIDS, done = true;
4610 } else {
4611
1/2
✓ Branch 0 taken 6546 times.
✗ Branch 1 not taken.
6546 Gtid_log_event *gtid_ev = (Gtid_log_event *)ev;
4612
1/2
✓ Branch 0 taken 6546 times.
✗ Branch 1 not taken.
6546 rpl_sidno sidno = gtid_ev->get_sidno(sid_map);
4613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6546 times.
6546 if (sidno < 0)
4614 ret = ERROR, done = true;
4615 else {
4616
2/2
✓ Branch 0 taken 4763 times.
✓ Branch 1 taken 1783 times.
6546 if (all_gtids) {
4617
2/4
✓ Branch 0 taken 4763 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4763 times.
4763 if (all_gtids->ensure_sidno(sidno) != RETURN_STATUS_OK)
4618 ret = ERROR, done = true;
4619
1/2
✓ Branch 0 taken 4763 times.
✗ Branch 1 not taken.
4763 all_gtids->_add_gtid(sidno, gtid_ev->get_gno());
4620
3/8
✓ Branch 0 taken 4763 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4763 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4763 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4763 DBUG_PRINT("info",
4621 ("Got Gtid from file '%s': Gtid(%d, %" PRId64 ").",
4622 filename, sidno, gtid_ev->get_gno()));
4623 }
4624
4625 /* If the first GTID was requested, stores it */
4626
3/4
✓ Branch 0 taken 1783 times.
✓ Branch 1 taken 4763 times.
✓ Branch 2 taken 1783 times.
✗ Branch 3 not taken.
6546 if (first_gtid && !seen_first_gtid) {
4627 1783 first_gtid->set(sidno, gtid_ev->get_gno());
4628 1783 seen_first_gtid = true;
4629 /* If the first_gtid was the only thing requested, we are done */
4630
1/2
✓ Branch 0 taken 1783 times.
✗ Branch 1 not taken.
1783 if (all_gtids == nullptr) ret = GOT_GTIDS, done = true;
4631 }
4632 }
4633 }
4634 6818 break;
4635 }
4636 853332 case binary_log::ANONYMOUS_GTID_LOG_EVENT: {
4637 /*
4638 When this is a relaylog, we just check if it contains
4639 at least one Anonymous_gtid_log_event after initialization
4640 (FDs, Rotates and PREVIOUS_GTIDS), so that we can distinguish the
4641 return values GOT_GTID and GOT_PREVIOUS_GTIDS.
4642 We don't need to read anything else from the relay log.
4643 */
4644
2/2
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 853047 times.
853332 if (is_relay_log) {
4645 285 ret = GOT_GTIDS;
4646 285 done = true;
4647 285 break;
4648 }
4649
5/6
✓ Branch 0 taken 159776 times.
✓ Branch 1 taken 693271 times.
✓ Branch 2 taken 38004 times.
✓ Branch 3 taken 121772 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 38004 times.
853047 assert(prev_gtids == nullptr
4650 ? true
4651 : all_gtids != nullptr || first_gtid != nullptr);
4652 }
4653 [[fallthrough]];
4654 default:
4655 // if we found any other event type without finding a
4656 // previous_gtids_log_event, then the rest of this binlog
4657 // cannot contain gtids
4658
4/4
✓ Branch 0 taken 8827652 times.
✓ Branch 1 taken 18630 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 8827611 times.
8846282 if (ret != GOT_GTIDS && ret != GOT_PREVIOUS_GTIDS) done = true;
4659 /*
4660 The GTIDs of the relaylog files will be handled later
4661 because of the possibility of transactions be spanned
4662 along distinct relaylog files.
4663 So, if we found an ordinary event without finding the
4664 GTID but we already found the PREVIOUS_GTIDS, this probably
4665 means that the event is from a transaction that started on
4666 previous relaylog file.
4667 */
4668
4/4
✓ Branch 0 taken 8827611 times.
✓ Branch 1 taken 18671 times.
✓ Branch 2 taken 812 times.
✓ Branch 3 taken 8826799 times.
8846282 if (ret == GOT_PREVIOUS_GTIDS && is_relay_log) done = true;
4669 8846282 break;
4670 }
4671
1/2
✓ Branch 0 taken 8896725 times.
✗ Branch 1 not taken.
8896725 delete ev;
4672
3/8
✓ Branch 0 taken 8896725 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8896725 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8896725 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8896725 DBUG_PRINT("info", ("done=%d", done));
4673 }
4674
4675
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 20606 times.
20618 if (binlog_file_reader.has_fatal_error()) {
4676 // This is not a fatal error; the log may just be truncated.
4677
4678 // @todo but what other errors could happen? IO error?
4679
8/16
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 12 times.
✗ Branch 15 not taken.
12 LogErr(WARNING_LEVEL, ER_BINLOG_ERROR_READING_GTIDS_FROM_BINARY_LOG, -1);
4680
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 sql_print_warning(binlog_file_reader.get_error_str());
4681 }
4682
4683
2/2
✓ Branch 0 taken 14491 times.
✓ Branch 1 taken 6127 times.
20618 if (all_gtids)
4684
1/2
✓ Branch 0 taken 14491 times.
✗ Branch 1 not taken.
14491 all_gtids->dbug_print("all_gtids");
4685 else
4686
3/8
✓ Branch 0 taken 6127 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6127 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6127 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6127 DBUG_PRINT("info", ("all_gtids==NULL"));
4687
2/2
✓ Branch 0 taken 7470 times.
✓ Branch 1 taken 13148 times.
20618 if (prev_gtids)
4688
1/2
✓ Branch 0 taken 7470 times.
✗ Branch 1 not taken.
7470 prev_gtids->dbug_print("prev_gtids");
4689 else
4690
3/8
✓ Branch 0 taken 13148 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13148 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13148 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
13148 DBUG_PRINT("info", ("prev_gtids==NULL"));
4691
2/2
✓ Branch 0 taken 18008 times.
✓ Branch 1 taken 2610 times.
20618 if (first_gtid == nullptr)
4692
3/8
✓ Branch 0 taken 18008 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18008 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18008 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18008 DBUG_PRINT("info", ("first_gtid==NULL"));
4693
2/2
✓ Branch 0 taken 827 times.
✓ Branch 1 taken 1783 times.
2610 else if (first_gtid->sidno == 0)
4694
3/8
✓ Branch 0 taken 827 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 827 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 827 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
827 DBUG_PRINT("info", ("first_gtid.sidno==0"));
4695 else
4696
1/2
✓ Branch 0 taken 1783 times.
✗ Branch 1 not taken.
1783 first_gtid->dbug_print(sid_map, "first_gtid");
4697
4698
3/8
✓ Branch 0 taken 20618 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20618 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20618 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20618 DBUG_PRINT("info", ("returning %d", ret));
4699 #ifndef NDEBUG
4700
8/8
✓ Branch 0 taken 10956 times.
✓ Branch 1 taken 9662 times.
✓ Branch 2 taken 7470 times.
✓ Branch 3 taken 3486 times.
✓ Branch 4 taken 6127 times.
✓ Branch 5 taken 1343 times.
✓ Branch 6 taken 3517 times.
✓ Branch 7 taken 2610 times.
20618 if (!is_relay_log && prev_gtids != nullptr && all_gtids == nullptr &&
4701 first_gtid == nullptr)
4702
8/16
✓ Branch 0 taken 3517 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3517 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3517 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3517 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3517 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3517 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3517 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3517 times.
✗ Branch 15 not taken.
3517 LogErr(INFORMATION_LEVEL, ER_BINLOG_EVENTS_READ_FROM_BINLOG_INFO,
4703 event_counter, filename);
4704 #endif
4705 20618 return ret;
4706 20625 }
4707
4708 527 bool MYSQL_BIN_LOG::find_first_log(std::string &binlog_file_name,
4709 std::string &errmsg) {
4710
1/2
✓ Branch 0 taken 527 times.
✗ Branch 1 not taken.
527 auto log_index = this->get_log_index();
4711
1/2
✓ Branch 0 taken 527 times.
✗ Branch 1 not taken.
527 std::list<std::string> filename_list = log_index.second;
4712
4713 527 list<string>::iterator fit = filename_list.begin();
4714
1/2
✓ Branch 0 taken 527 times.
✗ Branch 1 not taken.
527 if (fit != filename_list.end()) {
4715
1/2
✓ Branch 0 taken 527 times.
✗ Branch 1 not taken.
527 binlog_file_name.assign(*fit);
4716 } else {
4717 errmsg.assign("Could not find the first log file name in the index file");
4718 return true;
4719 }
4720 527 return false;
4721 527 }
4722
4723 2236 bool MYSQL_BIN_LOG::find_first_log_not_in_gtid_set(char *binlog_file_name,
4724 const Gtid_set *gtid_set,
4725 Gtid *first_gtid,
4726 std::string &errmsg) {
4727
1/2
✓ Branch 0 taken 2236 times.
✗ Branch 1 not taken.
2236 DBUG_TRACE;
4728 2236 LOG_INFO linfo;
4729
1/2
✓ Branch 0 taken 2236 times.
✗ Branch 1 not taken.
2236 auto log_index = this->get_log_index();
4730
1/2
✓ Branch 0 taken 2236 times.
✗ Branch 1 not taken.
2236 std::list<std::string> filename_list = log_index.second;
4731 2236 int error = log_index.first;
4732 2236 list<string>::reverse_iterator rit;
4733
1/2
✓ Branch 0 taken 2236 times.
✗ Branch 1 not taken.
2236 Gtid_set binlog_previous_gtid_set{gtid_set->get_sid_map()};
4734
4735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2236 times.
2236 if (error != LOG_INFO_EOF) {
4736 errmsg.assign(
4737 "Failed to read the binary log index file while "
4738 "looking for the oldest binary log that contains any GTID "
4739 "that is not in the given gtid set");
4740 error = -1;
4741 goto end;
4742 }
4743
4744
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2236 times.
2236 if (filename_list.empty()) {
4745 errmsg.assign(
4746 "Could not find first log file name in binary log index file "
4747 "while looking for the oldest binary log that contains any GTID "
4748 "that is not in the given gtid set");
4749 error = -2;
4750 goto end;
4751 }
4752
4753 /*
4754 Iterate over all the binary logs in reverse order, and read only
4755 the Previous_gtids_log_event, to find the first one, that is the
4756 subset of the given gtid set. Since every binary log begins with
4757 a Previous_gtids_log_event, that contains all GTIDs in all
4758 previous binary logs.
4759 We also ask for the first GTID in the binary log to know if we
4760 should send the FD event with the "created" field cleared or not.
4761 */
4762
3/8
✓ Branch 0 taken 2236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2236 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2236 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2236 DBUG_PRINT("info", ("Iterating backwards through binary logs, and reading "
4763 "only the Previous_gtids_log_event, to find the first "
4764 "one, that is the subset of the given gtid set."));
4765 2236 rit = filename_list.rbegin();
4766 2236 error = 0;
4767
3/4
✓ Branch 0 taken 2259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2258 times.
✓ Branch 3 taken 1 times.
2259 while (rit != filename_list.rend()) {
4768
1/2
✓ Branch 0 taken 2258 times.
✗ Branch 1 not taken.
2258 binlog_previous_gtid_set.clear();
4769
1/2
✓ Branch 0 taken 2258 times.
✗ Branch 1 not taken.
2258 const char *filename = rit->c_str();
4770
3/8
✓ Branch 0 taken 2258 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2258 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2258 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2258 DBUG_PRINT("info",
4771 ("Read Previous_gtids_log_event from filename='%s'", filename));
4772
3/7
✓ Branch 0 taken 2258 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2257 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
2258 switch (read_gtids_from_binlog(filename, nullptr, &binlog_previous_gtid_set,
4773 first_gtid,
4774 binlog_previous_gtid_set.get_sid_map(),
4775 2258 opt_source_verify_checksum, is_relay_log)) {
4776 case ERROR:
4777 errmsg.assign(
4778 "Error reading header of binary log while looking for "
4779 "the oldest binary log that contains any GTID that is not in "
4780 "the given gtid set");
4781 error = -3;
4782 goto end;
4783 case NO_GTIDS:
4784 errmsg.assign(
4785 "Found old binary log without GTIDs while looking for "
4786 "the oldest binary log that contains any GTID that is not in "
4787 "the given gtid set");
4788 error = -4;
4789 goto end;
4790 2257 case GOT_GTIDS:
4791 case GOT_PREVIOUS_GTIDS:
4792
3/4
✓ Branch 0 taken 2257 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2235 times.
✓ Branch 3 taken 22 times.
2257 if (binlog_previous_gtid_set.is_subset(gtid_set)) {
4793 2235 strcpy(binlog_file_name, filename);
4794 /*
4795 Verify that the selected binlog is not the first binlog,
4796 */
4797
2/6
✓ Branch 0 taken 2235 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2235 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2235 DBUG_EXECUTE_IF("replica_reconnect_with_gtid_set_executed",
4798 assert(strcmp(filename_list.begin()->c_str(),
4799 binlog_file_name) != 0););
4800 2235 goto end;
4801 }
4802 case TRUNCATED:
4803 23 break;
4804 }
4805
4806
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 rit++;
4807 }
4808
4809
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (rit == filename_list.rend()) {
4810
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 report_missing_gtids(&binlog_previous_gtid_set, gtid_set, errmsg);
4811 1 error = -5;
4812 }
4813
4814 end:
4815
5/10
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2235 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
2236 if (error) DBUG_PRINT("error", ("'%s'", errmsg.c_str()));
4816 2236 filename_list.clear();
4817
3/8
✓ Branch 0 taken 2236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2236 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2236 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2236 DBUG_PRINT("info", ("returning %d", error));
4818 2236 return error != 0 ? true : false;
4819 2236 }
4820
4821 10418 bool MYSQL_BIN_LOG::init_gtid_sets(Gtid_set *all_gtids, Gtid_set *lost_gtids,
4822 bool verify_checksum, bool need_lock,
4823 Transaction_boundary_parser *trx_parser,
4824 Gtid_monitoring_info *partial_trx,
4825 bool is_server_starting) {
4826
1/2
✓ Branch 0 taken 10418 times.
✗ Branch 1 not taken.
10418 DBUG_TRACE;
4827
3/10
✓ Branch 0 taken 10418 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10418 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10418 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
10418 DBUG_PRINT(
4828 "info",
4829 ("lost_gtids=%p; so we are recovering a %s log; is_relay_log=%d",
4830 lost_gtids, lost_gtids == nullptr ? "relay" : "binary", is_relay_log));
4831
4832 Checkable_rwlock *sid_lock =
4833
2/2
✓ Branch 0 taken 1225 times.
✓ Branch 1 taken 9193 times.
10418 is_relay_log ? all_gtids->get_sid_map()->get_sid_lock() : global_sid_lock;
4834 /*
4835 If this is a relay log, we must have the IO thread Master_info trx_parser
4836 in order to correctly feed it with relay log events.
4837 */
4838 #ifndef NDEBUG
4839
2/2
✓ Branch 0 taken 1225 times.
✓ Branch 1 taken 9193 times.
10418 if (is_relay_log) {
4840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1225 times.
1225 assert(trx_parser != nullptr);
4841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1225 times.
1225 assert(lost_gtids == nullptr);
4842 }
4843 #endif
4844
4845 /*
4846 Acquires the necessary locks to ensure that logs are not either
4847 removed or updated when we are reading from it.
4848 */
4849
2/2
✓ Branch 0 taken 10211 times.
✓ Branch 1 taken 207 times.
10418 if (need_lock) {
4850 // We don't need LOCK_log if we are only going to read the initial
4851 // Prevoius_gtids_log_event and ignore the Gtid_log_events.
4852
2/4
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10211 times.
✗ Branch 3 not taken.
10211 if (all_gtids != nullptr) mysql_mutex_lock(&LOCK_log);
4853
1/2
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
10211 mysql_mutex_lock(&LOCK_index);
4854
1/2
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
10211 sid_lock->wrlock();
4855 } else {
4856 if (all_gtids != nullptr) mysql_mutex_assert_owner(&LOCK_log);
4857 mysql_mutex_assert_owner(&LOCK_index);
4858
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 sid_lock->assert_some_wrlock();
4859 }
4860
4861 /* Initialize the sid_map to be used in read_gtids_from_binlog */
4862 10418 Sid_map *sid_map = nullptr;
4863
2/2
✓ Branch 0 taken 10211 times.
✓ Branch 1 taken 207 times.
10418 if (all_gtids)
4864 10211 sid_map = all_gtids->get_sid_map();
4865
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 else if (lost_gtids)
4866 207 sid_map = lost_gtids->get_sid_map();
4867
4868 // Gather the set of files to be accessed.
4869
1/2
✓ Branch 0 taken 10418 times.
✗ Branch 1 not taken.
10418 auto log_index = this->get_log_index(false);
4870
1/2
✓ Branch 0 taken 10418 times.
✗ Branch 1 not taken.
10418 std::list<std::string> filename_list = log_index.second;
4871 10418 int error = log_index.first;
4872 10418 list<string>::iterator it;
4873 10418 list<string>::reverse_iterator rit;
4874 10418 bool reached_first_file = false;
4875
4876
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10418 times.
10418 if (error != LOG_INFO_EOF) {
4877 DBUG_PRINT("error", ("Error reading %s index",
4878 is_relay_log ? "relaylog" : "binlog"));
4879 goto end;
4880 }
4881 /*
4882 On server starting, one new empty binlog file is created and
4883 its file name is put into index file before initializing
4884 GLOBAL.GTID_EXECUTED AND GLOBAL.GTID_PURGED, it is not the
4885 last binlog file before the server restarts, so we remove
4886 its file name from filename_list.
4887 */
4888
6/8
✓ Branch 0 taken 8986 times.
✓ Branch 1 taken 1432 times.
✓ Branch 2 taken 8986 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8986 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8986 times.
✓ Branch 7 taken 1432 times.
10418 if (is_server_starting && !is_relay_log && !filename_list.empty())
4889 8986 filename_list.pop_back();
4890
4891 10418 error = 0;
4892
2/2
✓ Branch 0 taken 10211 times.
✓ Branch 1 taken 207 times.
10418 if (all_gtids != nullptr) {
4893
3/12
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10211 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10211 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
10211 DBUG_PRINT("info", ("Iterating backwards through %s logs, "
4894 "looking for the last %s log that contains "
4895 "a Previous_gtids_log_event.",
4896 is_relay_log ? "relay" : "binary",
4897 is_relay_log ? "relay" : "binary"));
4898 // Iterate over all files in reverse order until we find one that
4899 // contains a Previous_gtids_log_event.
4900 10211 rit = filename_list.rbegin();
4901 10211 bool can_stop_reading = false;
4902
1/2
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
10211 reached_first_file = (rit == filename_list.rend());
4903
3/12
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10211 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10211 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
10211 DBUG_PRINT("info",
4904 ("filename='%s' reached_first_file=%d",
4905 reached_first_file ? "" : rit->c_str(), reached_first_file));
4906
4/4
✓ Branch 0 taken 19352 times.
✓ Branch 1 taken 5351 times.
✓ Branch 2 taken 14497 times.
✓ Branch 3 taken 4855 times.
24703 while (!can_stop_reading && !reached_first_file) {
4907
1/2
✓ Branch 0 taken 14497 times.
✗ Branch 1 not taken.
14497 const char *filename = rit->c_str();
4908
2/4
✓ Branch 0 taken 14497 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14497 times.
14497 assert(rit != filename_list.rend());
4909
1/2
✓ Branch 0 taken 14497 times.
✗ Branch 1 not taken.
14497 rit++;
4910
1/2
✓ Branch 0 taken 14497 times.
✗ Branch 1 not taken.
14497 reached_first_file = (rit == filename_list.rend());
4911
3/8
✓ Branch 0 taken 14497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14497 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14497 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14497 DBUG_PRINT("info", ("filename='%s' can_stop_reading=%d "
4912 "reached_first_file=%d, ",
4913 filename, can_stop_reading, reached_first_file));
4914
5/8
✓ Branch 0 taken 14497 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 940 times.
✓ Branch 4 taken 13514 times.
✓ Branch 5 taken 37 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
14497 switch (read_gtids_from_binlog(
4915 filename, all_gtids, reached_first_file ? lost_gtids : nullptr,
4916
2/2
✓ Branch 0 taken 2009 times.
✓ Branch 1 taken 12488 times.
14497 nullptr /* first_gtid */, sid_map, verify_checksum, is_relay_log)) {
4917 case ERROR: {
4918 error = 1;
4919 goto end;
4920 }
4921 940 case GOT_GTIDS: {
4922 940 can_stop_reading = true;
4923 940 break;
4924 }
4925 13514 case GOT_PREVIOUS_GTIDS: {
4926 /*
4927 If this is a binlog file, it is enough to have GOT_PREVIOUS_GTIDS.
4928 If this is a relaylog file, we need to find at least one GTID to
4929 start parsing the relay log to add GTID of transactions that might
4930 have spanned in distinct relaylog files.
4931 */
4932
2/2
✓ Branch 0 taken 4411 times.
✓ Branch 1 taken 9103 times.
13514 if (!is_relay_log) can_stop_reading = true;
4933 13514 break;
4934 }
4935 37 case NO_GTIDS: {
4936 /*
4937 Mysql server iterates backwards through binary logs, looking for
4938 the last binary log that contains a Previous_gtids_log_event for
4939 gathering the set of gtid_executed on server start. This may take
4940 very long time if it has many binary logs and almost all of them
4941 are out of filesystem cache. So if the binlog_gtid_simple_recovery
4942 is enabled, and the last binary log does not contain any GTID
4943 event, do not read any more binary logs, GLOBAL.GTID_EXECUTED and
4944 GLOBAL.GTID_PURGED should be empty in the case.
4945 */
4946
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2 times.
37 if (binlog_gtid_simple_recovery && is_server_starting &&
4947
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 !is_relay_log) {
4948
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 assert(all_gtids->is_empty());
4949
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 assert(lost_gtids->is_empty());
4950 5 goto end;
4951 }
4952 [[fallthrough]];
4953 }
4954 case TRUNCATED: {
4955 38 break;
4956 }
4957 }
4958 }
4959
4960 /*
4961 If we use GTIDs and have partial transactions on the relay log,
4962 must check if it ends on next relay log files.
4963 We also need to feed the boundary parser with the rest of the
4964 relay log to put it in the correct state before receiving new
4965 events from the master in the case of GTID auto positioning be
4966 disabled.
4967 */
4968
6/6
✓ Branch 0 taken 1225 times.
✓ Branch 1 taken 8981 times.
✓ Branch 2 taken 1205 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 1205 times.
✓ Branch 5 taken 9001 times.
10206 if (is_relay_log && filename_list.size() > 0) {
4969 /*
4970 Suppose the following relaylog:
4971
4972 rl-bin.000001 | rl-bin.000002 | rl-bin.000003 | rl-bin-000004
4973 ---------------+---------------+---------------+---------------
4974 PREV_GTIDS | PREV_GTIDS | PREV_GTIDS | PREV_GTIDS
4975 (empty) | (UUID:1) | (UUID:1) | (UUID:1)
4976 ---------------+---------------+---------------+---------------
4977 GTID(UUID:1) | QUERY(INSERT) | QUERY(INSERT) | XID
4978 ---------------+---------------+---------------+---------------
4979 QUERY(CREATE |
4980 TABLE t1 ...) |
4981 ---------------+
4982 GTID(UUID:2) |
4983 ---------------+
4984 QUERY(BEGIN) |
4985 ---------------+
4986
4987 As it is impossible to determine the current Retrieved_Gtid_Set by only
4988 looking to the PREVIOUS_GTIDS on the last relay log file, and scanning
4989 events on it, we tried to find a relay log file that contains at least
4990 one GTID event during the backwards search.
4991
4992 In the example, we will find a GTID only in rl-bin.000001, as the
4993 UUID:2 transaction was spanned across 4 relay log files.
4994
4995 The transaction spanning can be caused by "FLUSH RELAY LOGS" commands
4996 on slave while it is queuing the transaction.
4997
4998 So, in order to correctly add UUID:2 into Retrieved_Gtid_Set, we need
4999 to parse the relay log starting on the file we found the last GTID
5000 queued to know if the transaction was fully retrieved or not.
5001 */
5002
5003 /*
5004 Adjust the reverse iterator to point to the relaylog file we
5005 need to start parsing, as it was incremented after generating
5006 the relay log file name.
5007 */
5008
2/4
✓ Branch 0 taken 1205 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1205 times.
1205 assert(rit != filename_list.rbegin());
5009
1/2
✓ Branch 0 taken 1205 times.
✗ Branch 1 not taken.
1205 rit--;
5010
2/4
✓ Branch 0 taken 1205 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1205 times.
1205 assert(rit != filename_list.rend());
5011 /* Reset the transaction parser before feeding it with events */
5012
1/2
✓ Branch 0 taken 1205 times.
✗ Branch 1 not taken.
1205 trx_parser->reset();
5013
1/2
✓ Branch 0 taken 1205 times.
✗ Branch 1 not taken.
1205 partial_trx->clear();
5014
5015
3/8
✓ Branch 0 taken 1205 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1205 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1205 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1205 DBUG_PRINT("info", ("Iterating forwards through relay logs, "
5016 "updating the Retrieved_Gtid_Set and updating "
5017 "IO thread trx parser before start."));
5018
1/2
✓ Branch 0 taken 1205 times.
✗ Branch 1 not taken.
1205 for (it = find(filename_list.begin(), filename_list.end(), *rit);
5019
2/2
✓ Branch 0 taken 9668 times.
✓ Branch 1 taken 1205 times.
10873 it != filename_list.end(); it++) {
5020 9668 const char *filename = it->c_str();
5021
3/8
✓ Branch 0 taken 9668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9668 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9668 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9668 DBUG_PRINT("info", ("filename='%s'", filename));
5022
2/4
✓ Branch 0 taken 9668 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9668 times.
9668 if (read_gtids_and_update_trx_parser_from_relaylog(
5023 filename, all_gtids, true, trx_parser, partial_trx)) {
5024 error = 1;
5025 goto end;
5026 }
5027 }
5028 }
5029 }
5030
4/4
✓ Branch 0 taken 1225 times.
✓ Branch 1 taken 9188 times.
✓ Branch 2 taken 5530 times.
✓ Branch 3 taken 3658 times.
10413 if (lost_gtids != nullptr && !reached_first_file) {
5031 /*
5032 This branch is only reachable by a binary log. The relay log
5033 don't need to get lost_gtids information.
5034
5035 A 5.6 server sets GTID_PURGED by rotating the binary log.
5036
5037 A 5.6 server that had recently enabled GTIDs and set GTID_PURGED
5038 would have a sequence of binary logs like:
5039
5040 master-bin.N : No PREVIOUS_GTIDS (GTID wasn't enabled)
5041 master-bin.N+1: Has an empty PREVIOUS_GTIDS and a ROTATE
5042 (GTID was enabled on startup)
5043 master-bin.N+2: Has a PREVIOUS_GTIDS with the content set by a
5044 SET @@GLOBAL.GTID_PURGED + has GTIDs of some
5045 transactions.
5046
5047 If this 5.6 server be upgraded to 5.7 keeping its binary log files,
5048 this routine will have to find the first binary log that contains a
5049 PREVIOUS_GTIDS + a GTID event to ensure that the content of the
5050 GTID_PURGED will be correctly set (assuming binlog_gtid_simple_recovery
5051 is not enabled).
5052 */
5053
3/8
✓ Branch 0 taken 3658 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3658 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3658 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3658 DBUG_PRINT("info", ("Iterating forwards through binary logs, looking for "
5054 "the first binary log that contains both a "
5055 "Previous_gtids_log_event and a Gtid_log_event."));
5056
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3658 times.
3658 assert(!is_relay_log);
5057
2/2
✓ Branch 0 taken 3870 times.
✓ Branch 1 taken 15 times.
3885 for (it = filename_list.begin(); it != filename_list.end(); it++) {
5058 /*
5059 We should pass a first_gtid to read_gtids_from_binlog when
5060 binlog_gtid_simple_recovery is disabled, or else it will return
5061 right after reading the PREVIOUS_GTIDS event to avoid stall on
5062 reading the whole binary log.
5063 */
5064 3870 Gtid first_gtid = {0, 0};
5065 3870 const char *filename = it->c_str();
5066
3/8
✓ Branch 0 taken 3870 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3870 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3870 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3870 DBUG_PRINT("info", ("filename='%s'", filename));
5067
3/7
✓ Branch 0 taken 3870 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
✓ Branch 4 taken 3744 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
3870 switch (read_gtids_from_binlog(
5068 filename, nullptr, lost_gtids,
5069 binlog_gtid_simple_recovery ? nullptr : &first_gtid, sid_map,
5070
2/2
✓ Branch 0 taken 3517 times.
✓ Branch 1 taken 353 times.
3870 verify_checksum, is_relay_log)) {
5071 case ERROR: {
5072 error = 1;
5073 [[fallthrough]];
5074 }
5075 126 case GOT_GTIDS: {
5076 3643 goto end;
5077 }
5078 3744 case NO_GTIDS:
5079 case GOT_PREVIOUS_GTIDS: {
5080 /*
5081 Mysql server iterates forwards through binary logs, looking for
5082 the first binary log that contains both Previous_gtids_log_event
5083 and gtid_log_event for gathering the set of gtid_purged on server
5084 start. It also iterates forwards through binary logs, looking for
5085 the first binary log that contains both Previous_gtids_log_event
5086 and gtid_log_event for gathering the set of gtid_purged when
5087 purging binary logs. This may take very long time if it has many
5088 binary logs and almost all of them are out of filesystem cache.
5089 So if the binlog_gtid_simple_recovery is enabled, we just
5090 initialize GLOBAL.GTID_PURGED from the first binary log, do not
5091 read any more binary logs.
5092 */
5093
2/2
✓ Branch 0 taken 3517 times.
✓ Branch 1 taken 227 times.
3744 if (binlog_gtid_simple_recovery) goto end;
5094 [[fallthrough]];
5095 }
5096 case TRUNCATED: {
5097 227 break;
5098 }
5099 }
5100 }
5101 }
5102 6755 end:
5103
3/4
✓ Branch 0 taken 10211 times.
✓ Branch 1 taken 207 times.
✓ Branch 2 taken 10211 times.
✗ Branch 3 not taken.
10418 if (all_gtids) all_gtids->dbug_print("all_gtids");
5104
3/4
✓ Branch 0 taken 9193 times.
✓ Branch 1 taken 1225 times.
✓ Branch 2 taken 9193 times.
✗ Branch 3 not taken.
10418 if (lost_gtids) lost_gtids->dbug_print("lost_gtids");
5105
2/2
✓ Branch 0 taken 10211 times.
✓ Branch 1 taken 207 times.
10418 if (need_lock) {
5106
1/2
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
10211 sid_lock->unlock();
5107
1/2
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
10211 mysql_mutex_unlock(&LOCK_index);
5108
2/4
✓ Branch 0 taken 10211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10211 times.
✗ Branch 3 not taken.
10211 if (all_gtids != nullptr) mysql_mutex_unlock(&LOCK_log);
5109 }
5110 10418 filename_list.clear();
5111
3/8
✓ Branch 0 taken 10418 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10418 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10418 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10418 DBUG_PRINT("info", ("returning %d", error));
5112 10418 return error != 0 ? true : false;
5113 10418 }
5114
5115 /**
5116 Open a (new) binlog file.
5117
5118 - Open the log file and the index file. Register the new
5119 file name in it
5120 - When calling this when the file is in use, you must have a locks
5121 on LOCK_log and LOCK_index.
5122
5123 @retval
5124 0 ok
5125 @retval
5126 1 error
5127 */
5128
5129 78866 bool MYSQL_BIN_LOG::open_binlog(
5130 const char *log_name, const char *new_name, ulong max_size_arg,
5131 bool null_created_arg, bool need_lock_index, bool need_sid_lock,
5132 Format_description_log_event *extra_description_event,
5133 uint32 new_index_number) {
5134 // lock_index must be acquired *before* sid_lock.
5135
3/4
✓ Branch 0 taken 26265 times.
✓ Branch 1 taken 52601 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26265 times.
78866 assert(need_sid_lock || !need_lock_index);
5136
1/2
✓ Branch 0 taken 78866 times.
✗ Branch 1 not taken.
78866 DBUG_TRACE;
5137
3/8
✓ Branch 0 taken 78866 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78866 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 78866 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
78866 DBUG_PRINT("enter", ("base filename: %s", log_name));
5138
5139 mysql_mutex_assert_owner(get_log_lock());
5140
5141
3/4
✓ Branch 0 taken 78866 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 78863 times.
78866 if (init_and_set_log_file_name(log_name, new_name, new_index_number)) {
5142
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_GENERATE_NEW_FILE_NAME);
5143 3 return true;
5144 }
5145
5146
3/8
✓ Branch 0 taken 78863 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78863 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 78863 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
78863 DBUG_PRINT("info", ("generated filename: %s", log_file_name));
5147
5148
1/2
✓ Branch 0 taken 78863 times.
✗ Branch 1 not taken.
78863 if (open_purge_index_file(true) ||
5149
8/12
✓ Branch 0 taken 78863 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78863 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78863 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 78863 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 78862 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 78860 times.
157725 register_create_index_entry(log_file_name) || sync_purge_index_file() ||
5150
3/4
✓ Branch 0 taken 78862 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 78860 times.
78862 DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0)) {
5151 /**
5152 @todo: although this was introduced to appease valgrind
5153 when injecting emulated faults using fault_injection_registering_index
5154 it may be good to consider what actually happens when
5155 open_purge_index_file succeeds but register or sync fails.
5156
5157 Perhaps we might need the code below in MYSQL_BIN_LOG::cleanup
5158 for "real life" purposes as well?
5159 */
5160
6/10
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
3 DBUG_EXECUTE_IF("fault_injection_registering_index", {
5161 if (my_b_inited(&purge_index_file)) {
5162 end_io_cache(&purge_index_file);
5163 my_close(purge_index_file.file, MYF(0));
5164 }
5165 });
5166
5167
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_SYNC_INDEX_FILE_IN_OPEN);
5168 3 return true;
5169 }
5170
2/6
✓ Branch 0 taken 78860 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78860 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
78860 DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index",
5171 DBUG_SUICIDE(););
5172
5173 78860 write_error = false;
5174
5175 /* open the main log file */
5176
3/4
✓ Branch 0 taken 78859 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 78858 times.
78860 if (open(m_key_file_log, log_name, new_name, new_index_number)) {
5177
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 close_purge_index_file();
5178 1 return true; /* all warnings issued */
5179 }
5180
5181 78858 max_size = max_size_arg;
5182
5183 78858 bool write_file_name_to_index_file = false;
5184
5185 /* This must be before goto err. */
5186 #ifndef NDEBUG
5187 78858 binary_log_debug::debug_pretend_version_50034_in_binlog =
5188
1/2
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
78858 DBUG_EVALUATE_IF("pretend_version_50034_in_binlog", true, false);
5189 #endif
5190
1/2
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
78858 Format_description_log_event s;
5191
5192
1/2
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
78858 if (m_binlog_file->is_empty()) {
5193 /*
5194 The binary log file was empty (probably newly created)
5195 This is the normal case and happens when the user doesn't specify
5196 an extension for the binary log files.
5197 In this case we write a standard header to it.
5198 */
5199
2/4
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78858 times.
78858 if (m_binlog_file->write(pointer_cast<const uchar *>(BINLOG_MAGIC),
5200 BIN_LOG_HEADER_SIZE))
5201 goto err;
5202 78858 bytes_written += BIN_LOG_HEADER_SIZE;
5203 78858 write_file_name_to_index_file = true;
5204 }
5205
5206 /*
5207 don't set LOG_EVENT_BINLOG_IN_USE_F for the relay log
5208 */
5209
2/2
✓ Branch 0 taken 26099 times.
✓ Branch 1 taken 52759 times.
78858 if (!is_relay_log) {
5210 26099 s.common_header->flags |= LOG_EVENT_BINLOG_IN_USE_F;
5211 }
5212
5213
2/2
✓ Branch 0 taken 52759 times.
✓ Branch 1 taken 26099 times.
78858 if (is_relay_log) {
5214 /* relay-log */
5215
2/2
✓ Branch 0 taken 6436 times.
✓ Branch 1 taken 46323 times.
52759 if (relay_log_checksum_alg == binary_log::BINLOG_CHECKSUM_ALG_UNDEF) {
5216 /* inherit master's A descriptor if one has been received */
5217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6436 times.
6436 if (opt_replica_sql_verify_checksum == 0)
5218 /* otherwise use slave's local preference of RL events verification */
5219 relay_log_checksum_alg = binary_log::BINLOG_CHECKSUM_ALG_OFF;
5220 else
5221 6436 relay_log_checksum_alg =
5222 6436 static_cast<enum_binlog_checksum_alg>(binlog_checksum_options);
5223 }
5224 }
5225
5226
2/4
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78858 times.
78858 if (!s.is_valid()) goto err;
5227 78858 s.dont_set_created = null_created_arg;
5228 /* Set LOG_EVENT_RELAY_LOG_F flag for relay log's FD */
5229
2/2
✓ Branch 0 taken 52759 times.
✓ Branch 1 taken 26099 times.
78858 if (is_relay_log) s.set_relay_log_event();
5230
2/4
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78858 times.
78858 if (write_event_to_binlog(&s)) goto err;
5231
5232 /*
5233 We need to revisit this code and improve it.
5234 See further comments in the mysqld.
5235 /Alfranio
5236 */
5237
3/4
✓ Branch 0 taken 78858 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68426 times.
✓ Branch 3 taken 10432 times.
78858 if (current_thd) {
5238 68426 Checkable_rwlock *sid_lock = nullptr;
5239
1/2
✓ Branch 0 taken 68426 times.
✗ Branch 1 not taken.
68426 Gtid_set logged_gtids_binlog(global_sid_map, global_sid_lock);
5240 Gtid_set *previous_logged_gtids;
5241
5242
2/2
✓ Branch 0 taken 51317 times.
✓ Branch 1 taken 17109 times.
68426 if (is_relay_log) {
5243 51317 previous_logged_gtids = previous_gtid_set_relaylog;
5244 51317 sid_lock = previous_gtid_set_relaylog->get_sid_map()->get_sid_lock();
5245 } else {
5246 17109 previous_logged_gtids = &logged_gtids_binlog;
5247 17109 sid_lock = global_sid_lock;
5248 }
5249
5250
2/2
✓ Branch 0 taken 42162 times.
✓ Branch 1 taken 26264 times.
68426 if (need_sid_lock)
5251
1/2
✓ Branch 0 taken 42162 times.
✗ Branch 1 not taken.
42162 sid_lock->wrlock();
5252 else
5253
1/2
✓ Branch 0 taken 26264 times.
✗ Branch 1 not taken.
26264 sid_lock->assert_some_wrlock();
5254
5255
2/2
✓ Branch 0 taken 17109 times.
✓ Branch 1 taken 51317 times.
68426 if (!is_relay_log) {
5256 17109 const Gtid_set *executed_gtids = gtid_state->get_executed_gtids();
5257 const Gtid_set *gtids_only_in_table =
5258 17109 gtid_state->get_gtids_only_in_table();
5259 /* logged_gtids_binlog= executed_gtids - gtids_only_in_table */
5260
2/4
✓ Branch 0 taken 17109 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17109 times.
17109 if (logged_gtids_binlog.add_gtid_set(executed_gtids) !=
5261 RETURN_STATUS_OK) {
5262 if (need_sid_lock) sid_lock->unlock();
5263 goto err;
5264 }
5265
1/2
✓ Branch 0 taken 17109 times.
✗ Branch 1 not taken.
17109 logged_gtids_binlog.remove_gtid_set(gtids_only_in_table);
5266 }
5267
3/10
✓ Branch 0 taken 68426 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68426 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 68426 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
68426 DBUG_PRINT("info", ("Generating PREVIOUS_GTIDS for %s file.",
5268 is_relay_log ? "relaylog" : "binlog"));
5269
1/2
✓ Branch 0 taken 68426 times.
✗ Branch 1 not taken.
68426 Previous_gtids_log_event prev_gtids_ev(previous_logged_gtids);
5270
2/2
✓ Branch 0 taken 51317 times.
✓ Branch 1 taken 17109 times.
68426 if (is_relay_log) prev_gtids_ev.set_relay_log_event();
5271
3/4
✓ Branch 0 taken 42162 times.
✓ Branch 1 taken 26264 times.
✓ Branch 2 taken 42162 times.
✗ Branch 3 not taken.
68426 if (need_sid_lock) sid_lock->unlock();
5272
2/4
✓ Branch 0 taken 68426 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 68426 times.
68426 if (write_event_to_binlog(&prev_gtids_ev)) goto err;
5273
2/4
✓ Branch 0 taken 68426 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68426 times.
✗ Branch 3 not taken.
68426 } else // !(current_thd)
5274 {
5275 /*
5276 If the slave was configured before server restart, the server will
5277 generate a new relay log file without having current_thd, but this
5278 new relay log file must have a PREVIOUS_GTIDS event as we now
5279 generate the PREVIOUS_GTIDS event always.
5280
5281 This is only needed for relay log files because the server will add
5282 the PREVIOUS_GTIDS of binary logs (when current_thd==NULL) after
5283 server's GTID initialization.
5284
5285 During server's startup at mysqld_main(), from the binary/relay log
5286 initialization point of view, it will:
5287 1) Call init_server_components() that will generate a new binary log
5288 file but won't write the PREVIOUS_GTIDS event yet;
5289 2) Initialize server's GTIDs;
5290 3) Write the binary log PREVIOUS_GTIDS;
5291 4) Call init_replica() in where the new relay log file will be created
5292 after initializing relay log's Retrieved_Gtid_Set;
5293 */
5294
2/2
✓ Branch 0 taken 1442 times.
✓ Branch 1 taken 8990 times.
10432 if (is_relay_log) {
5295 Sid_map *previous_gtid_sid_map =
5296 1442 previous_gtid_set_relaylog->get_sid_map();
5297 1442 Checkable_rwlock *sid_lock = previous_gtid_sid_map->get_sid_lock();
5298
5299
1/2
✓ Branch 0 taken 1442 times.
✗ Branch 1 not taken.
1442 if (need_sid_lock)
5300
1/2
✓ Branch 0 taken 1442 times.
✗ Branch 1 not taken.
1442 sid_lock->wrlock();
5301 else
5302 sid_lock->assert_some_wrlock(); /* purecov: inspected */
5303
5304
3/8
✓ Branch 0 taken 1442 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1442 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1442 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1442 DBUG_PRINT("info", ("Generating PREVIOUS_GTIDS for relaylog file."));
5305
1/2
✓ Branch 0 taken 1442 times.
✗ Branch 1 not taken.
1442 Previous_gtids_log_event prev_gtids_ev(previous_gtid_set_relaylog);
5306 1442 prev_gtids_ev.set_relay_log_event();
5307
5308
2/4
✓ Branch 0 taken 1442 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1442 times.
✗ Branch 3 not taken.
1442 if (need_sid_lock) sid_lock->unlock();
5309
5310
2/4
✓ Branch 0 taken 1442 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1442 times.
1442 if (write_event_to_binlog(&prev_gtids_ev)) goto err;
5311
1/2
✓ Branch 0 taken 1442 times.
✗ Branch 1 not taken.
1442 }
5312 }
5313
2/2
✓ Branch 0 taken 5607 times.
✓ Branch 1 taken 73251 times.
78858 if (extra_description_event) {
5314 /*
5315 This is a relay log written to by the I/O slave thread.
5316 Write the event so that others can later know the format of this relay
5317 log.
5318 Note that this event is very close to the original event from the
5319 master (it has binlog version of the master, event types of the
5320 master), so this is suitable to parse the next relay log's event. It
5321 has been produced by
5322 Format_description_log_event::Format_description_log_event(char* buf,).
5323 Why don't we want to write the mi_description_event if this
5324 event is for format<4 (3.23 or 4.x): this is because in that case, the
5325 mi_description_event describes the data received from the
5326 master, but not the data written to the relay log (*conversion*),
5327 which is in format 4 (slave's).
5328 */
5329 /*
5330 Set 'created' to 0, so that in next relay logs this event does not
5331 trigger cleaning actions on the slave in
5332 Format_description_log_event::apply_event_impl().
5333 */
5334 5607 extra_description_event->created = 0;
5335 /* Don't set log_pos in event header */
5336 5607 extra_description_event->set_artificial_event();
5337
2/4
✓ Branch 0 taken 5607 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5607 times.
5607 if (binary_event_serialize(extra_description_event, m_binlog_file))
5338 goto err;
5339 5607 bytes_written += extra_description_event->common_header->data_written;
5340 }
5341
2/4
✓ Branch 0 taken 78856 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78856 times.
78858 if (m_binlog_file->flush_and_sync()) goto err;
5342
5343
1/2
✓ Branch 0 taken 78856 times.
✗ Branch 1 not taken.
78856 if (write_file_name_to_index_file) {
5344
2/6
✓ Branch 0 taken 78856 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78856 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
78856 DBUG_EXECUTE_IF("crash_create_critical_before_update_index",
5345 DBUG_SUICIDE(););
5346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78856 times.
78856 assert(my_b_inited(&index_file) != 0);
5347
5348 /*
5349 The new log file name is appended into crash safe index file after
5350 all the content of index file is copied into the crash safe index
5351 file. Then move the crash safe index file to index file.
5352 */
5353
4/6
✓ Branch 0 taken 78856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 78855 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
78856 DBUG_EXECUTE_IF("simulate_disk_full_on_open_binlog",
5354 { DBUG_SET("+d,simulate_no_free_space_error"); });
5355
5/6
✓ Branch 0 taken 78855 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78854 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 78854 times.
157711 if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
5356
3/4
✓ Branch 0 taken 78855 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 78854 times.
78854 add_log_to_index((uchar *)log_file_name, strlen(log_file_name),
5357 need_lock_index)) {
5358
6/10
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
2 DBUG_EXECUTE_IF("simulate_disk_full_on_open_binlog", {
5359 DBUG_SET("-d,simulate_file_write_error");
5360 DBUG_SET("-d,simulate_no_free_space_error");
5361 DBUG_SET("-d,simulate_disk_full_on_open_binlog");
5362 });
5363 2 goto err;
5364 }
5365
5366
2/6
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78854 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
78854 DBUG_EXECUTE_IF("crash_create_after_update_index", DBUG_SUICIDE(););
5367 }
5368
5369 78854 atomic_log_state = LOG_OPENED;
5370 /*
5371 At every rotate memorize the last transaction counter state to use it as
5372 offset at logging the transaction logical timestamps.
5373 */
5374
1/2
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
78854 m_dependency_tracker.rotate();
5375
5376
1/2
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
78854 close_purge_index_file();
5377
5378
1/2
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
78854 update_binlog_end_pos();
5379 78854 return false;
5380
5381 2 err:
5382
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (is_inited_purge_index_file())
5383
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 purge_index_entry(nullptr, nullptr, need_lock_index);
5384
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 close_purge_index_file();
5385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (binlog_error_action == ABORT_SERVER) {
5386 exec_binlog_error_action_abort(
5387 "Either disk is full, file system is read only or "
5388 "there was an encryption error while opening the binlog. "
5389 "Aborting the server.");
5390 } else {
5391
9/18
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
2 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_USE_FOR_LOGGING,
5392 (new_name) ? new_name : name, errno);
5393
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 close(LOG_CLOSE_INDEX, false, need_lock_index);
5394 }
5395 2 return true;
5396 78863 }
5397
5398 /**
5399 Move crash safe index file to index file.
5400
5401 @param need_lock_index If true, LOCK_index will be acquired;
5402 otherwise it should already be held.
5403
5404 @retval 0 ok
5405 @retval -1 error
5406 */
5407 102885 int MYSQL_BIN_LOG::move_crash_safe_index_file_to_index_file(
5408 bool need_lock_index) {
5409 102885 int error = 0;
5410 102885 File fd = -1;
5411
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 DBUG_TRACE;
5412 102885 int failure_trials = MYSQL_BIN_LOG::MAX_RETRIES_FOR_DELETE_RENAME_FAILURE;
5413 102885 bool file_rename_status = false, file_delete_status = false;
5414
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 THD *thd = current_thd;
5415
5416
2/2
✓ Branch 0 taken 20832 times.
✓ Branch 1 taken 82053 times.
102885 if (need_lock_index)
5417
1/2
✓ Branch 0 taken 20832 times.
✗ Branch 1 not taken.
20832 mysql_mutex_lock(&LOCK_index);
5418 else
5419 mysql_mutex_assert_owner(&LOCK_index);
5420
5421
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 if (my_b_inited(&index_file)) {
5422
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 end_io_cache(&index_file);
5423
2/4
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102885 times.
102885 if (mysql_file_close(index_file.file, MYF(0)) < 0) {
5424 error = -1;
5425 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_CLOSE_INDEX_FILE_WHILE_REBUILDING,
5426 index_file_name);
5427 /*
5428 Delete Crash safe index file here and recover the binlog.index
5429 state(index_file io_cache) from old binlog.index content.
5430 */
5431 mysql_file_delete(key_file_binlog_index, crash_safe_index_file_name,
5432 MYF(0));
5433
5434 goto recoverable_err;
5435 }
5436
5437 /*
5438 Sometimes an outsider can lock index files for temporary viewing
5439 purpose. For eg: MEB locks binlog.index/relaylog.index to view
5440 the content of the file. During that small period of time, deletion
5441 of the file is not possible on some platforms(Eg: Windows)
5442 Server should retry the delete operation for few times instead of
5443 panicking immediately.
5444 */
5445
3/4
✓ Branch 0 taken 102885 times.
✓ Branch 1 taken 102884 times.
✓ Branch 2 taken 102885 times.
✗ Branch 3 not taken.
205769 while ((file_delete_status == false) && (failure_trials > 0)) {
5446
2/4
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102885 times.
102885 if (DBUG_EVALUATE_IF("force_index_file_delete_failure", 1, 0)) break;
5447
5448
2/12
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102885 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
102885 DBUG_EXECUTE_IF("simulate_index_file_delete_failure", {
5449 /* This simulation causes the delete to fail */
5450 static char first_char = index_file_name[0];
5451 index_file_name[0] = 0;
5452 sql_print_information("Retrying delete");
5453 if (failure_trials == 1) index_file_name[0] = first_char;
5454 };);
5455
1/2
✓ Branch 0 taken 102884 times.
✗ Branch 1 not taken.
102885 file_delete_status = !(mysql_file_delete(key_file_binlog_index,
5456 index_file_name, MYF(MY_WME)));
5457 102884 --failure_trials;
5458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102884 times.
102884 if (!file_delete_status) {
5459 my_sleep(1000);
5460 /* Clear the error before retrying. */
5461 if (failure_trials > 0) thd->clear_error();
5462 }
5463 }
5464
5465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102884 times.
102884 if (!file_delete_status) {
5466 error = -1;
5467 LogErr(ERROR_LEVEL,
5468 ER_BINLOG_FAILED_TO_DELETE_INDEX_FILE_WHILE_REBUILDING,
5469 index_file_name);
5470 /*
5471 Delete Crash safe file index file here and recover the binlog.index
5472 state(index_file io_cache) from old binlog.index content.
5473 */
5474 mysql_file_delete(key_file_binlog_index, crash_safe_index_file_name,
5475 MYF(0));
5476
5477 goto recoverable_err;
5478 }
5479 }
5480
5481
2/6
✓ Branch 0 taken 102884 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102884 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
102884 DBUG_EXECUTE_IF("crash_create_before_rename_index_file", DBUG_SUICIDE(););
5482 /*
5483 Sometimes an outsider can lock index files for temporary viewing
5484 purpose. For eg: MEB locks binlog.index/relaylog.index to view
5485 the content of the file. During that small period of time, rename
5486 of the file is not possible on some platforms(Eg: Windows)
5487 Server should retry the rename operation for few times instead of panicking
5488 immediately.
5489 */
5490 102884 failure_trials = MYSQL_BIN_LOG::MAX_RETRIES_FOR_DELETE_RENAME_FAILURE;
5491
3/4
✓ Branch 0 taken 102884 times.
✓ Branch 1 taken 102885 times.
✓ Branch 2 taken 102884 times.
✗ Branch 3 not taken.
205769 while ((file_rename_status == false) && (failure_trials > 0)) {
5492
2/12
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102885 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
102884 DBUG_EXECUTE_IF("simulate_crash_safe_index_file_rename_failure", {
5493 /* This simulation causes the rename to fail */
5494 static char first_char = index_file_name[0];
5495 index_file_name[0] = 0;
5496 sql_print_information("Retrying rename");
5497 if (failure_trials == 1) index_file_name[0] = first_char;
5498 };);
5499 102885 file_rename_status =
5500
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 !(my_rename(crash_safe_index_file_name, index_file_name, MYF(MY_WME)));
5501 102885 --failure_trials;
5502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102885 times.
102885 if (!file_rename_status) {
5503 my_sleep(1000);
5504 /* Clear the error before retrying. */
5505 if (failure_trials > 0) thd->clear_error();
5506 }
5507 }
5508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102885 times.
102885 if (!file_rename_status) {
5509 error = -1;
5510 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_RENAME_INDEX_FILE_WHILE_REBUILDING,
5511 index_file_name);
5512 goto fatal_err;
5513 }
5514
2/6
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102885 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
102885 DBUG_EXECUTE_IF("crash_create_after_rename_index_file", DBUG_SUICIDE(););
5515
5516 102885 recoverable_err:
5517
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 if ((fd = mysql_file_open(key_file_binlog_index, index_file_name,
5518 102885 O_RDWR | O_CREAT, MYF(MY_WME))) < 0 ||
5519
4/8
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102885 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 102885 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 102884 times.
205769 mysql_file_sync(fd, MYF(MY_WME)) ||
5520
3/6
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102884 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 102884 times.
102885 init_io_cache_ext(&index_file, fd, IO_SIZE, READ_CACHE,
5521 mysql_file_seek(fd, 0L, MY_SEEK_END, MYF(0)), false,
5522 MYF(MY_WME | MY_WAIT_IF_FULL),
5523 key_file_binlog_index_cache)) {
5524 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_OPEN_INDEX_FILE_AFTER_REBUILDING,
5525 index_file_name);
5526 goto fatal_err;
5527 }
5528
5529
3/4
✓ Branch 0 taken 20832 times.
✓ Branch 1 taken 82052 times.
✓ Branch 2 taken 20833 times.
✗ Branch 3 not taken.
102884 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
5530 102885 return error;
5531
5532 fatal_err:
5533 /*
5534 This situation is very very rare to happen (unless there is some serious
5535 memory related issues like OOM) and should be treated as fatal error.
5536 Hence it is better to bring down the server without respecting
5537 'binlog_error_action' value here.
5538 */
5539 exec_binlog_error_action_abort(
5540 "MySQL server failed to update the "
5541 "binlog.index file's content properly. "
5542 "It might not be in sync with available "
5543 "binlogs and the binlog.index file state is in "
5544 "unrecoverable state. Aborting the server.");
5545 /*
5546 Server is aborted in the above function.
5547 This is dead code to make compiler happy.
5548 */
5549 return error;
5550 102885 }
5551
5552 /**
5553 Append log file name to index file.
5554
5555 - To make crash safe, we copy all the content of index file
5556 to crash safe index file firstly and then append the log
5557 file name to the crash safe index file. Finally move the
5558 crash safe index file to index file.
5559
5560 @retval
5561 0 ok
5562 @retval
5563 -1 error
5564 */
5565 78855 int MYSQL_BIN_LOG::add_log_to_index(uchar *log_name, size_t log_name_len,
5566 bool need_lock_index) {
5567
1/2
✓ Branch 0 taken 78855 times.
✗ Branch 1 not taken.
78855 DBUG_TRACE;
5568
5569
2/4
✓ Branch 0 taken 78855 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78855 times.
78855 if (open_crash_safe_index_file()) {
5570 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_TMP_INDEX,
5571 "MYSQL_BIN_LOG::add_log_to_index");
5572 goto err;
5573 }
5574
5575
3/4
✓ Branch 0 taken 78855 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 78854 times.
78855 if (copy_file(&index_file, &crash_safe_index_file, 0)) {
5576
8/16
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_COPY_INDEX_TO_TMP,
5577 "MYSQL_BIN_LOG::add_log_to_index");
5578 1 goto err;
5579 }
5580
5581
1/2
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
78854 if (my_b_write(&crash_safe_index_file, log_name, log_name_len) ||
5582
2/4
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78854 times.
✗ Branch 3 not taken.
78854 my_b_write(&crash_safe_index_file, pointer_cast<const uchar *>("\n"),
5583 78854 1) ||
5584
4/8
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78854 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78854 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 78853 times.
236561 flush_io_cache(&crash_safe_index_file) ||
5585
2/4
✓ Branch 0 taken 78853 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78853 times.
78854 mysql_file_sync(crash_safe_index_file.file, MYF(MY_WME))) {
5586 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_APPEND_LOG_TO_TMP_INDEX, log_name);
5587 goto err;
5588 }
5589
5590
2/4
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78854 times.
78853 if (close_crash_safe_index_file()) {
5591 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_CLOSE_TMP_INDEX,
5592 "MYSQL_BIN_LOG::add_log_to_index");
5593 goto err;
5594 }
5595
5596
2/4
✓ Branch 0 taken 78854 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78854 times.
78854 if (move_crash_safe_index_file_to_index_file(need_lock_index)) {
5597 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_MOVE_TMP_TO_INDEX,
5598 "MYSQL_BIN_LOG::add_log_to_index");
5599 goto err;
5600 }
5601
5602 78854 return 0;
5603
5604 1 err:
5605 1 return -1;
5606 78855 }
5607
5608 1449425 int MYSQL_BIN_LOG::get_current_log(LOG_INFO *linfo,
5609 bool need_lock_log /*true*/) {
5610
2/2
✓ Branch 0 taken 77297 times.
✓ Branch 1 taken 1372128 times.
1449425 if (need_lock_log) mysql_mutex_lock(&LOCK_log);
5611 1449425 int ret = raw_get_current_log(linfo);
5612
2/2
✓ Branch 0 taken 77297 times.
✓ Branch 1 taken 1372128 times.
1449425 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
5613 1449425 return ret;
5614 }
5615
5616 1449981 int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO *linfo) {
5617 1449981 strmake(linfo->log_file_name, log_file_name,
5618 sizeof(linfo->log_file_name) - 1);
5619 1449981 linfo->pos = m_binlog_file->position();
5620 1449981 linfo->encrypted_header_size = m_binlog_file->get_encrypted_header_size();
5621 1449981 return 0;
5622 }
5623
5624 9461 static bool check_write_error_code(uint error_code) {
5625
2/2
✓ Branch 0 taken 9316 times.
✓ Branch 1 taken 13 times.
9329 return error_code == ER_TRANS_CACHE_FULL ||
5626
6/6
✓ Branch 0 taken 9329 times.
✓ Branch 1 taken 132 times.
✓ Branch 2 taken 9243 times.
✓ Branch 3 taken 73 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 9242 times.
18790 error_code == ER_STMT_CACHE_FULL || error_code == ER_ERROR_ON_WRITE ||
5627 9461 error_code == ER_BINLOG_LOGGING_IMPOSSIBLE;
5628 }
5629
5630 9823 bool MYSQL_BIN_LOG::check_write_error(const THD *thd) {
5631
1/2
✓ Branch 0 taken 9833 times.
✗ Branch 1 not taken.
9823 DBUG_TRACE;
5632
5633
3/4
✓ Branch 0 taken 9826 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4304 times.
✓ Branch 3 taken 5522 times.
9833 if (!thd->is_error()) return false;
5634
5635 5522 bool checked = check_write_error_code(thd->get_stmt_da()->mysql_errno());
5636
5637
2/2
✓ Branch 0 taken 5300 times.
✓ Branch 1 taken 225 times.
5525 if (!checked) {
5638 /* Check all conditions for one that matches the expected error */
5639 const Sql_condition *err;
5640 Diagnostics_area::Sql_condition_iterator it =
5641
1/2
✓ Branch 0 taken 5299 times.
✗ Branch 1 not taken.
5300 thd->get_stmt_da()->sql_conditions();
5642
6/8
✓ Branch 0 taken 9240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3941 times.
✓ Branch 3 taken 5299 times.
✓ Branch 4 taken 3941 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3941 times.
✓ Branch 7 taken 5299 times.
9240 while ((err = it++) != nullptr && !checked) {
5643 3941 checked = check_write_error_code(err->mysql_errno());
5644 }
5645 }
5646
3/10
✓ Branch 0 taken 5520 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5529 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5529 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
5524 DBUG_PRINT("return", ("checked: %s", YESNO(checked)));
5647 5529 return checked;
5648 9833 }
5649
5650 115 void MYSQL_BIN_LOG::report_cache_write_error(THD *thd, bool is_transactional) {
5651
1/2
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
115 DBUG_TRACE;
5652
5653 115 write_error = true;
5654
5655
2/4
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 115 times.
115 if (check_write_error(thd)) return;
5656
5657
3/4
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 77 times.
✓ Branch 3 taken 38 times.
115 if (my_errno() == EFBIG) {
5658
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 7 times.
77 if (is_transactional) {
5659
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 my_error(ER_TRANS_CACHE_FULL, MYF(MY_WME));
5660 } else {
5661
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 my_error(ER_STMT_CACHE_FULL, MYF(MY_WME));
5662 }
5663 } else {
5664 char errbuf[MYSYS_STRERROR_SIZE];
5665
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno,
5666
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 my_strerror(errbuf, sizeof(errbuf), errno));
5667 }
5668
5669 #ifdef WITH_WSREP
5670 /*
5671 If wsrep transaction is active and binlog emulation is on, binlog
5672 write error may leave transaction without any registered htons.
5673 This makes wsrep rollback hooks to be skipped and the transaction
5674 will remain alive in wsrep world after rollback. Register binlog
5675 hton here to ensure that rollback happens in full only when the
5676 session is in multi stmt transaction mode (i.e, either
5677 autocommit=OFF or when the transaction is started with explicit
5678 BEGIN).
5679 */
5680
7/10
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 98 times.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 16 times.
✓ Branch 9 taken 1 times.
115 if (WSREP_EMULATE_BINLOG(thd)) {
5681
5/6
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 4 times.
16 if (is_transactional && thd->in_multi_stmt_transaction_mode())
5682
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 trans_register_ha(thd, true, binlog_hton, NULL);
5683
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 trans_register_ha(thd, false, binlog_hton, NULL);
5684 }
5685 #endif /* WITH_WSREP */
5686
1/2
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
115 }
5687
5688 6166643 static int compare_log_name(const char *log_1, const char *log_2) {
5689 6166643 const char *log_1_basename = log_1 + dirname_length(log_1);
5690 6166656 const char *log_2_basename = log_2 + dirname_length(log_2);
5691
5692 6166664 return strcmp(log_1_basename, log_2_basename);
5693 }
5694
5695 /**
5696 Find the position in the log-index-file for the given log name.
5697
5698 @param[out] linfo The found log file name will be stored here, along
5699 with the byte offset of the next log file name in the index file.
5700 @param log_name Filename to find in the index file, or NULL if we
5701 want to read the first entry.
5702 @param need_lock_index If false, this function acquires LOCK_index;
5703 otherwise the lock should already be held by the caller.
5704
5705 @note
5706 On systems without the truncate function the file will end with one or
5707 more empty lines. These will be ignored when reading the file.
5708
5709 @retval
5710 0 ok
5711 @retval
5712 LOG_INFO_EOF End of log-index-file found
5713 @retval
5714 LOG_INFO_IO Got IO error while reading file
5715 */
5716
5717 241685 int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
5718 bool need_lock_index) {
5719 241685 int error = 0;
5720 241685 char *full_fname = linfo->log_file_name;
5721 char full_log_name[FN_REFLEN], fname[FN_REFLEN];
5722
1/2
✓ Branch 0 taken 241685 times.
✗ Branch 1 not taken.
241685 DBUG_TRACE;
5723 241685 full_log_name[0] = full_fname[0] = 0;
5724
5725 /*
5726 Mutex needed because we need to make sure the file pointer does not
5727 move from under our feet
5728 */
5729
2/2
✓ Branch 0 taken 85494 times.
✓ Branch 1 taken 156191 times.
241685 if (need_lock_index)
5730
1/2
✓ Branch 0 taken 85494 times.
✗ Branch 1 not taken.
85494 mysql_mutex_lock(&LOCK_index);
5731 else
5732 mysql_mutex_assert_owner(&LOCK_index);
5733
5734
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 241684 times.
241685 if (!my_b_inited(&index_file)) {
5735 1 error = LOG_INFO_IO;
5736 1 goto end;
5737 }
5738
5739 // extend relative paths for log_name to be searched
5740
2/2
✓ Branch 0 taken 93418 times.
✓ Branch 1 taken 148266 times.
241684 if (log_name) {
5741
2/4
✓ Branch 0 taken 93418 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 93418 times.
93418 if (normalize_binlog_name(full_log_name, log_name, is_relay_log)) {
5742 error = LOG_INFO_EOF;
5743 goto end;
5744 }
5745 }
5746
5747
3/10
✓ Branch 0 taken 241684 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 241684 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 241684 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
241684 DBUG_PRINT("enter", ("log_name: %s, full_log_name: %s",
5748 log_name ? log_name : "NULL", full_log_name));
5749
5750 /* As the file is flushed, we can't get an error here */
5751
1/2
✓ Branch 0 taken 241684 times.
✗ Branch 1 not taken.
241684 my_b_seek(&index_file, (my_off_t)0);
5752
5753 for (;;) {
5754 size_t length;
5755 2279258 my_off_t offset = my_b_tell(&index_file);
5756
5757
3/4
✓ Branch 0 taken 2279258 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 2279244 times.
2279258 DBUG_EXECUTE_IF("simulate_find_log_pos_error", error = LOG_INFO_EOF;
5758 break;);
5759 /* If we get 0 or 1 characters, this is the end of the file */
5760
3/4
✓ Branch 0 taken 2279258 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19265 times.
✓ Branch 3 taken 2259993 times.
2279258 if ((length = my_b_gets(&index_file, fname, FN_REFLEN)) <= 1) {
5761 /* Did not find the given entry; Return not found or error */
5762
1/2
✓ Branch 0 taken 19265 times.
✗ Branch 1 not taken.
19265 error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
5763 19265 break;
5764 }
5765
5766 // extend relative paths and match against full path
5767
2/4
✓ Branch 0 taken 2259993 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2259993 times.
2259993 if (normalize_binlog_name(full_fname, fname, is_relay_log)) {
5768 error = LOG_INFO_EOF;
5769 break;
5770 }
5771 // if the log entry matches, null string matching anything
5772
7/8
✓ Branch 0 taken 2115939 times.
✓ Branch 1 taken 144054 times.
✓ Branch 2 taken 2115939 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78365 times.
✓ Branch 5 taken 2037574 times.
✓ Branch 6 taken 222419 times.
✓ Branch 7 taken 2037574 times.
2259993 if (!log_name || !compare_log_name(full_fname, full_log_name)) {
5773
3/8
✓ Branch 0 taken 222419 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 222419 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 222419 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
222419 DBUG_PRINT("info", ("Found log file entry"));
5774 222419 linfo->index_file_start_offset = offset;
5775 222419 linfo->index_file_offset = my_b_tell(&index_file);
5776 222419 break;
5777 }
5778 2037574 linfo->entry_index++;
5779 2037574 }
5780
5781 241685 end:
5782
3/4
✓ Branch 0 taken 85494 times.
✓ Branch 1 taken 156191 times.
✓ Branch 2 taken 85494 times.
✗ Branch 3 not taken.
241685 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
5783 241685 return error;
5784 241685 }
5785
5786 /**
5787 Find the position in the log-index-file for the given log name.
5788
5789 @param[out] linfo The filename will be stored here, along with the
5790 byte offset of the next filename in the index file.
5791
5792 @param need_lock_index If true, LOCK_index will be acquired;
5793 otherwise it should already be held by the caller.
5794
5795 @note
5796 - Before calling this function, one has to call find_log_pos()
5797 to set up 'linfo'
5798 - Mutex needed because we need to make sure the file pointer does not move
5799 from under our feet
5800
5801 @retval 0 ok
5802 @retval LOG_INFO_EOF End of log-index-file found
5803 @retval LOG_INFO_IO Got IO error while reading file
5804 */
5805 637420 int MYSQL_BIN_LOG::find_next_log(LOG_INFO *linfo, bool need_lock_index) {
5806 637420 int error = 0;
5807 size_t length;
5808 char fname[FN_REFLEN];
5809 637420 char *full_fname = linfo->log_file_name;
5810
5811
2/2
✓ Branch 0 taken 294699 times.
✓ Branch 1 taken 342721 times.
637420 if (need_lock_index)
5812
1/2
✓ Branch 0 taken 294699 times.
✗ Branch 1 not taken.
294699 mysql_mutex_lock(&LOCK_index);
5813 else
5814 mysql_mutex_assert_owner(&LOCK_index);
5815
5816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 637420 times.
637420 if (!my_b_inited(&index_file)) {
5817 error = LOG_INFO_IO;
5818 goto err;
5819 }
5820 /* As the file is flushed, we can't get an error here */
5821
1/2
✓ Branch 0 taken 637420 times.
✗ Branch 1 not taken.
637420 my_b_seek(&index_file, linfo->index_file_offset);
5822
5823 637420 linfo->index_file_start_offset = linfo->index_file_offset;
5824
3/4
✓ Branch 0 taken 637420 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 77753 times.
✓ Branch 3 taken 559667 times.
637420 if ((length = my_b_gets(&index_file, fname, FN_REFLEN)) <= 1) {
5825
1/2
✓ Branch 0 taken 77753 times.
✗ Branch 1 not taken.
77753 error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
5826 77753 goto err;
5827 }
5828
5829
1/2
✓ Branch 0 taken 559667 times.
✗ Branch 1 not taken.
559667 if (fname[0] != 0) {
5830
2/4
✓ Branch 0 taken 559667 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 559667 times.
559667 if (normalize_binlog_name(full_fname, fname, is_relay_log)) {
5831 error = LOG_INFO_EOF;
5832 goto err;
5833 }
5834 559667 length = strlen(full_fname);
5835 }
5836
5837 559667 linfo->index_file_offset = my_b_tell(&index_file);
5838
5839 637420 err:
5840
3/4
✓ Branch 0 taken 294699 times.
✓ Branch 1 taken 342721 times.
✓ Branch 2 taken 294699 times.
✗ Branch 3 not taken.
637420 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
5841 637420 return error;
5842 }
5843
5844 /**
5845 Find the relay log name following the given name from relay log index file.
5846
5847 @param[in,out] log_name The name is full path name.
5848
5849 @return return 0 if it finds next relay log. Otherwise return the error code.
5850 */
5851 int MYSQL_BIN_LOG::find_next_relay_log(char log_name[FN_REFLEN + 1]) {
5852 LOG_INFO info;
5853 int error;
5854 char relative_path_name[FN_REFLEN + 1];
5855
5856 if (fn_format(relative_path_name, log_name + dirname_length(log_name),
5857 mysql_data_home, "", 0) == NullS)
5858 return 1;
5859
5860 mysql_mutex_lock(&LOCK_index);
5861
5862 error = find_log_pos(&info, relative_path_name, false);
5863 if (error == 0) {
5864 error = find_next_log(&info, false);
5865 if (error == 0) strcpy(log_name, info.log_file_name);
5866 }
5867
5868 mysql_mutex_unlock(&LOCK_index);
5869 return error;
5870 }
5871
5872 14630 std::pair<int, std::list<std::string>> MYSQL_BIN_LOG::get_log_index(
5873 bool need_lock_index) {
5874
1/2
✓ Branch 0 taken 14630 times.
✗ Branch 1 not taken.
14630 DBUG_TRACE;
5875 14630 LOG_INFO log_info;
5876
5877
2/2
✓ Branch 0 taken 4212 times.
✓ Branch 1 taken 10418 times.
14630 if (need_lock_index)
5878
1/2
✓ Branch 0 taken 4212 times.
✗ Branch 1 not taken.
4212 mysql_mutex_lock(&LOCK_index);
5879 else
5880 mysql_mutex_assert_owner(&LOCK_index);
5881
5882 14630 std::list<std::string> filename_list;
5883 14630 int error = 0;
5884 14630 for (error =
5885
1/2
✓ Branch 0 taken 14630 times.
✗ Branch 1 not taken.
14630 this->find_log_pos(&log_info, nullptr, false /*need_lock_index*/);
5886
2/2
✓ Branch 0 taken 274114 times.
✓ Branch 1 taken 14630 times.
288744 error == 0;
5887 274114 error = this->find_next_log(&log_info, false /*need_lock_index*/)) {
5888
3/6
✓ Branch 0 taken 274114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 274114 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 274114 times.
✗ Branch 5 not taken.
274114 filename_list.push_back(std::string(log_info.log_file_name));
5889 }
5890
5891
3/4
✓ Branch 0 taken 4212 times.
✓ Branch 1 taken 10418 times.
✓ Branch 2 taken 4212 times.
✗ Branch 3 not taken.
14630 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
5892
5893
1/2
✓ Branch 0 taken 14630 times.
✗ Branch 1 not taken.
29260 return std::make_pair(error, filename_list);
5894 14630 }
5895
5896 /**
5897 Removes files, as part of a RESET MASTER or RESET SLAVE statement,
5898 by deleting all logs referred to in the index file and the index
5899 file. Then, it creates a new index file and a new log file.
5900
5901 The new index file will only contain the new log file.
5902
5903 @param thd Thread
5904 @param delete_only If true, do not create a new index file and
5905 a new log file.
5906
5907 @note
5908 If not called from slave thread, write start event to new log
5909
5910 @retval
5911 0 ok
5912 @retval
5913 1 error
5914 */
5915 29142 bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool delete_only) {
5916 29142 LOG_INFO linfo;
5917 29142 bool error = false;
5918 int err;
5919 29142 const char *save_name = nullptr;
5920 29142 Checkable_rwlock *sid_lock = nullptr;
5921
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 DBUG_TRACE;
5922
5923 /*
5924 Flush logs for storage engines, so that the last transaction
5925 is persisted inside storage engines.
5926 */
5927
2/4
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29142 times.
29142 assert(!thd->is_log_reset());
5928
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 thd->set_log_reset();
5929
2/4
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29142 times.
29142 if (ha_flush_logs()) {
5930 thd->clear_log_reset();
5931 return true;
5932 }
5933
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 thd->clear_log_reset();
5934
5935
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 ha_reset_logs(thd);
5936
5937 /*
5938 We need to get both locks to be sure that no one is trying to
5939 write to the index log file.
5940 */
5941
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 mysql_mutex_lock(&LOCK_log);
5942
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 mysql_mutex_lock(&LOCK_index);
5943
5944
2/2
✓ Branch 0 taken 19979 times.
✓ Branch 1 taken 9163 times.
29142 if (is_relay_log)
5945 19979 sid_lock = previous_gtid_set_relaylog->get_sid_map()->get_sid_lock();
5946 else
5947 9163 sid_lock = global_sid_lock;
5948
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 sid_lock->wrlock();
5949
5950 /* Save variables so that we can reopen the log */
5951 29142 save_name = name;
5952 29142 name = nullptr; // Protect against free
5953
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 close(LOG_CLOSE_TO_BE_OPENED, false /*need_lock_log=false*/,
5954 false /*need_lock_index=false*/);
5955
5956 /*
5957 First delete all old log files and then update the index file.
5958 As we first delete the log files and do not use sort of logging,
5959 a crash may lead to an inconsistent state where the index has
5960 references to non-existent files.
5961
5962 We need to invert the steps and use the purge_index_file methods
5963 in order to make the operation safe.
5964 */
5965
5966
3/4
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 29133 times.
29142 if ((err = find_log_pos(&linfo, NullS, false /*need_lock_index=false*/)) !=
5967 0) {
5968 9 uint errcode = purge_log_get_error_code(err);
5969
8/16
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9 times.
✗ Branch 15 not taken.
9 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_LOCATE_OLD_BINLOG_OR_RELAY_LOG_FILES);
5970
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 my_error(errcode, MYF(0));
5971 9 error = true;
5972 9 goto err;
5973 }
5974
5975 for (;;) {
5976
3/4
✓ Branch 0 taken 45133 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 45125 times.
45133 if ((error = my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0) {
5977
3/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1 times.
8 if (my_errno() == ENOENT) {
5978 21 push_warning_printf(
5979
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 current_thd, Sql_condition::SL_WARNING, ER_LOG_PURGE_NO_FILE,
5980
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 ER_THD(current_thd, ER_LOG_PURGE_NO_FILE), linfo.log_file_name);
5981
8/16
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
7 LogErr(INFORMATION_LEVEL, ER_BINLOG_CANT_DELETE_FILE,
5982 linfo.log_file_name);
5983
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 set_my_errno(0);
5984 7 error = false;
5985 } else {
5986
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 push_warning_printf(current_thd, Sql_condition::SL_WARNING,
5987 ER_BINLOG_PURGE_FATAL_ERR,
5988 "a problem with deleting %s; "
5989 "consider examining correspondence "
5990 "of your binlog index file "
5991 "to the actual binlog files",
5992 linfo.log_file_name);
5993
8/16
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_DELETE_FILE, linfo.log_file_name);
5994
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_error(ER_BINLOG_PURGE_FATAL_ERR, MYF(0));
5995 1 error = true;
5996 1 goto err;
5997 }
5998 }
5999
3/4
✓ Branch 0 taken 45132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29132 times.
✓ Branch 3 taken 16000 times.
45132 if (find_next_log(&linfo, false /*need_lock_index=false*/)) break;
6000 }
6001
6002 /* Start logging with a new file */
6003
1/2
✓ Branch 0 taken 29132 times.
✗ Branch 1 not taken.
29132 close(LOG_CLOSE_INDEX | LOG_CLOSE_TO_BE_OPENED, false /*need_lock_log=false*/,
6004 false /*need_lock_index=false*/);
6005
3/4
✓ Branch 0 taken 29132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 29131 times.
29132 if ((error = my_delete_allow_opened(index_file_name,
6006 MYF(0)))) // Reset (open will update)
6007 {
6008
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (my_errno() == ENOENT) {
6009 push_warning_printf(
6010 current_thd, Sql_condition::SL_WARNING, ER_LOG_PURGE_NO_FILE,
6011 ER_THD(current_thd, ER_LOG_PURGE_NO_FILE), index_file_name);
6012 LogErr(INFORMATION_LEVEL, ER_BINLOG_CANT_DELETE_FILE, index_file_name);
6013 set_my_errno(0);
6014 error = false;
6015 } else {
6016
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 push_warning_printf(current_thd, Sql_condition::SL_WARNING,
6017 ER_BINLOG_PURGE_FATAL_ERR,
6018 "a problem with deleting %s; "
6019 "consider examining correspondence "
6020 "of your binlog index file "
6021 "to the actual binlog files",
6022
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 index_file_name);
6023
8/16
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_DELETE_FILE, index_file_name);
6024
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_error(ER_BINLOG_PURGE_FATAL_ERR, MYF(0));
6025 1 error = true;
6026 1 goto err;
6027 }
6028 }
6029
5/8
✓ Branch 0 taken 29131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 29128 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
29131 DBUG_EXECUTE_IF("wait_for_kill_gtid_state_clear", {
6030 const char action[] = "now WAIT_FOR kill_gtid_state_clear";
6031 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
6032 };);
6033
6034 /*
6035 For relay logs we clear the gtid state associated per channel(i.e rli)
6036 in the purge_relay_logs()
6037 */
6038
2/2
✓ Branch 0 taken 9158 times.
✓ Branch 1 taken 19973 times.
29131 if (!is_relay_log) {
6039
3/4
✓ Branch 0 taken 9158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 9152 times.
9158 if (gtid_state->clear(thd)) {
6040 6 error = true;
6041 }
6042 /*
6043 Don't clear global_sid_map because gtid_state->clear() above didn't
6044 touched owned_gtids GTID set.
6045 */
6046
4/6
✓ Branch 0 taken 9152 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 9152 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9152 times.
9158 error = error || gtid_state->init();
6047 }
6048
6049
2/2
✓ Branch 0 taken 26265 times.
✓ Branch 1 taken 2866 times.
29131 if (!delete_only) {
6050
2/4
✓ Branch 0 taken 26265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26265 times.
✗ Branch 3 not taken.
26265 if (!open_index_file(index_file_name, nullptr,
6051 false /*need_lock_index=false*/))
6052 26265 error = open_binlog(save_name, nullptr, max_size, false,
6053 false /*need_lock_index=false*/,
6054 false /*need_sid_lock=false*/, nullptr,
6055
5/6
✓ Branch 0 taken 26265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26264 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 26258 times.
26265 thd->lex->next_binlog_file_nr) ||
6056 error;
6057 }
6058 /* String has been duplicated, free old file-name */
6059
2/2
✓ Branch 0 taken 2867 times.
✓ Branch 1 taken 26264 times.
29131 if (name != nullptr) {
6060
1/2
✓ Branch 0 taken 26264 times.
✗ Branch 1 not taken.
26264 my_free(const_cast<char *>(save_name));
6061 26264 save_name = nullptr;
6062 }
6063
6064 2867 err:
6065
2/2
✓ Branch 0 taken 2878 times.
✓ Branch 1 taken 26264 times.
29142 if (name == nullptr)
6066 2878 name = const_cast<char *>(save_name); // restore old file-name
6067
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 sid_lock->unlock();
6068
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 count_binlog_space(false);
6069
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 mysql_mutex_unlock(&LOCK_index);
6070
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 mysql_mutex_unlock(&LOCK_log);
6071 29142 return error;
6072 29142 }
6073
6074 /**
6075 Set the name of crash safe index file.
6076
6077 @retval
6078 0 ok
6079 @retval
6080 1 error
6081 */
6082 79081 int MYSQL_BIN_LOG::set_crash_safe_index_file_name(const char *base_file_name) {
6083 79081 int error = 0;
6084
1/2
✓ Branch 0 taken 79081 times.
✗ Branch 1 not taken.
79081 DBUG_TRACE;
6085
1/2
✓ Branch 0 taken 79081 times.
✗ Branch 1 not taken.
79081 if (fn_format(crash_safe_index_file_name, base_file_name, mysql_data_home,
6086 ".index_crash_safe",
6087
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79081 times.
79081 MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_REPLACE_EXT)) ==
6088 nullptr) {
6089 error = 1;
6090 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_SET_TMP_INDEX_NAME);
6091 }
6092 79081 return error;
6093 79081 }
6094
6095 /**
6096 Open a (new) crash safe index file.
6097
6098 @note
6099 The crash safe index file is a special file
6100 used for guaranteeing index file crash safe.
6101 @retval
6102 0 ok
6103 @retval
6104 1 error
6105 */
6106 102886 int MYSQL_BIN_LOG::open_crash_safe_index_file() {
6107 102886 int error = 0;
6108 102886 File file = -1;
6109
6110
1/2
✓ Branch 0 taken 102886 times.
✗ Branch 1 not taken.
102886 DBUG_TRACE;
6111
6112
1/2
✓ Branch 0 taken 102886 times.
✗ Branch 1 not taken.
102886 if (!my_b_inited(&crash_safe_index_file)) {
6113 102886 myf flags = MY_WME | MY_NABP | MY_WAIT_IF_FULL;
6114
2/2
✓ Branch 0 taken 76583 times.
✓ Branch 1 taken 26303 times.
102886 if (is_relay_log) flags = flags | MY_REPORT_WAITING_IF_FULL;
6115
6116
1/2
✓ Branch 0 taken 102886 times.
✗ Branch 1 not taken.
102886 if ((file = my_open(crash_safe_index_file_name, O_RDWR | O_CREAT,
6117
2/4
✓ Branch 0 taken 102886 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102886 times.
205772 MYF(MY_WME))) < 0 ||
6118
2/4
✓ Branch 0 taken 102886 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102886 times.
102886 init_io_cache(&crash_safe_index_file, file, IO_SIZE, WRITE_CACHE, 0,
6119 false, flags)) {
6120 error = 1;
6121 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_OPEN_TEMPORARY_INDEX_FILE);
6122 }
6123 }
6124 102886 return error;
6125 102886 }
6126
6127 /**
6128 Close the crash safe index file.
6129
6130 @note
6131 The crash safe file is just closed, is not deleted.
6132 Because it is moved to index file later on.
6133 @retval
6134 0 ok
6135 @retval
6136 1 error
6137 */
6138 102884 int MYSQL_BIN_LOG::close_crash_safe_index_file() {
6139 102884 int error = 0;
6140
6141
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102884 DBUG_TRACE;
6142
6143
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 if (my_b_inited(&crash_safe_index_file)) {
6144
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 end_io_cache(&crash_safe_index_file);
6145
1/2
✓ Branch 0 taken 102885 times.
✗ Branch 1 not taken.
102885 error = my_close(crash_safe_index_file.file, MYF(0));
6146 }
6147 102885 crash_safe_index_file = IO_CACHE();
6148
6149 102885 return error;
6150 102885 }
6151
6152 /**
6153 Remove logs from index file.
6154
6155 - To make it crash safe, we copy the content of the index file
6156 from index_file_start_offset recorded in log_info to a
6157 crash safe index file first and then move the crash
6158 safe index file to the index file.
6159
6160 @param log_info Store here the found log file name and
6161 position to the NEXT log file name in
6162 the index file.
6163
6164 @param need_update_threads If we want to update the log coordinates
6165 of all threads. False for relay logs,
6166 true otherwise.
6167
6168 @retval
6169 0 ok
6170 @retval
6171 LOG_INFO_IO Got IO error while reading/writing file
6172 */
6173 24031 int MYSQL_BIN_LOG::remove_logs_from_index(LOG_INFO *log_info,
6174 bool need_update_threads) {
6175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24031 times.
24031 if (open_crash_safe_index_file()) {
6176 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_TMP_INDEX,
6177 "MYSQL_BIN_LOG::remove_logs_from_index");
6178 goto err;
6179 }
6180
6181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24031 times.
24031 if (copy_file(&index_file, &crash_safe_index_file,
6182 log_info->index_file_start_offset)) {
6183 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_COPY_INDEX_TO_TMP,
6184 "MYSQL_BIN_LOG::remove_logs_from_index");
6185 goto err;
6186 }
6187
6188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24031 times.
24031 if (close_crash_safe_index_file()) {
6189 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_CLOSE_TMP_INDEX,
6190 "MYSQL_BIN_LOG::remove_logs_from_index");
6191 goto err;
6192 }
6193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24031 times.
24031 DBUG_EXECUTE_IF("fault_injection_copy_part_file", DBUG_SUICIDE(););
6194
6195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24030 times.
24031 if (move_crash_safe_index_file_to_index_file(
6196 false /*need_lock_index=false*/)) {
6197 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_MOVE_TMP_TO_INDEX,
6198 "MYSQL_BIN_LOG::remove_logs_from_index");
6199 goto err;
6200 }
6201
6202 // now update offsets in index file for running threads
6203
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 23823 times.
24030 if (need_update_threads)
6204 207 adjust_linfo_offsets(log_info->index_file_start_offset);
6205 24030 return 0;
6206
6207 err:
6208 return LOG_INFO_IO;
6209 }
6210
6211 /**
6212 Remove all logs before the given log from disk and from the index file.
6213
6214 @param to_log Delete all log file name before this file.
6215 @param included If true, to_log is deleted too.
6216 @param need_lock_index Set to true, if the lock_index of the binary log
6217 shall be acquired, false if the called is already the owner of the lock_index.
6218 @param need_update_threads If we want to update the log coordinates of
6219 all threads. False for relay logs, true otherwise.
6220 @param decrease_log_space If not null, decrement this variable of
6221 the amount of log space freed
6222 @param auto_purge True if this is an automatic purge.
6223
6224 @note
6225 If any of the logs before the deleted one is in use,
6226 only purge logs up to this one.
6227
6228 @retval 0 ok
6229 @retval LOG_INFO_EOF to_log not found
6230 @retval LOG_INFO_EMFILE too many files opened
6231 @retval LOG_INFO_FATAL if any other than ENOENT error from
6232 mysql_file_stat() or mysql_file_delete()
6233 */
6234
6235 24033 int MYSQL_BIN_LOG::purge_logs(const char *to_log, bool included,
6236 bool need_lock_index, bool need_update_threads,
6237 ulonglong *decrease_log_space, bool auto_purge) {
6238 24033 int error = 0, no_of_log_files_to_purge = 0, no_of_log_files_purged = 0;
6239 24033 int no_of_threads_locking_log = 0;
6240 24033 bool exit_loop = false;
6241 24033 LOG_INFO log_info;
6242
1/2
✓ Branch 0 taken 24033 times.
✗ Branch 1 not taken.
24033 THD *thd = current_thd;
6243
1/2
✓ Branch 0 taken 24033 times.
✗ Branch 1 not taken.
24033 DBUG_TRACE;
6244
3/8
✓ Branch 0 taken 24033 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24033 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 24033 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
24033 DBUG_PRINT("info", ("to_log= %s", to_log));
6245
6246
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 23922 times.
24033 if (need_lock_index)
6247
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 mysql_mutex_lock(&LOCK_index);
6248 else
6249 mysql_mutex_assert_owner(&LOCK_index);
6250 24033 if ((error =
6251
3/4
✓ Branch 0 taken 24033 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24031 times.
24033 find_log_pos(&log_info, to_log, false /*need_lock_index=false*/))) {
6252
8/16
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
2 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CALLED_WITH_FILE_NOT_IN_INDEX,
6253 to_log);
6254 2 goto err;
6255 }
6256
6257 24031 no_of_log_files_to_purge = log_info.entry_index;
6258
6259
2/4
✓ Branch 0 taken 24031 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24031 times.
24031 if ((error = open_purge_index_file(true))) {
6260 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CANT_SYNC_INDEX_FILE);
6261 goto err;
6262 }
6263
6264 /*
6265 File name exists in index file; delete until we find this file
6266 or a file that is used.
6267 */
6268
2/4
✓ Branch 0 taken 24031 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24031 times.
24031 if ((error = find_log_pos(&log_info, NullS, false /*need_lock_index=false*/)))
6269 goto err;
6270
6271
5/6
✓ Branch 0 taken 38964 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24031 times.
✓ Branch 3 taken 14933 times.
✓ Branch 4 taken 15032 times.
✓ Branch 5 taken 23932 times.
62995 while ((compare_log_name(to_log, log_info.log_file_name) ||
6272
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 23932 times.
24031 (exit_loop = included))) {
6273
2/4
✓ Branch 0 taken 15032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15032 times.
15032 if (is_active(log_info.log_file_name)) {
6274 if (!auto_purge)
6275 push_warning_printf(
6276 thd, Sql_condition::SL_WARNING, ER_WARN_PURGE_LOG_IS_ACTIVE,
6277 ER_THD(thd, ER_WARN_PURGE_LOG_IS_ACTIVE), log_info.log_file_name);
6278 break;
6279 }
6280
6281
2/4
✓ Branch 0 taken 15032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15032 times.
15032 if ((no_of_threads_locking_log = log_in_use(log_info.log_file_name))) {
6282 if (!auto_purge)
6283 push_warning_printf(thd, Sql_condition::SL_WARNING,
6284 ER_WARN_PURGE_LOG_IN_USE,
6285 ER_THD(thd, ER_WARN_PURGE_LOG_IN_USE),
6286 log_info.log_file_name, no_of_threads_locking_log,
6287 no_of_log_files_purged, no_of_log_files_to_purge);
6288 break;
6289 }
6290 15032 no_of_log_files_purged++;
6291
6292
2/4
✓ Branch 0 taken 15032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15032 times.
15032 if ((error = register_purge_index_entry(log_info.log_file_name))) {
6293 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CANT_COPY_TO_REGISTER_FILE,
6294 log_info.log_file_name);
6295 goto err;
6296 }
6297
6298
6/8
✓ Branch 0 taken 15032 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15032 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 99 times.
✓ Branch 5 taken 14933 times.
✓ Branch 6 taken 99 times.
✓ Branch 7 taken 14933 times.
15032 if (find_next_log(&log_info, false /*need_lock_index=false*/) || exit_loop)
6299 99 break;
6300 }
6301
6302
2/6
✓ Branch 0 taken 24031 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24031 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
24031 DBUG_EXECUTE_IF("crash_purge_before_update_index", DBUG_SUICIDE(););
6303
6304
2/4
✓ Branch 0 taken 24031 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24031 times.
24031 if ((error = sync_purge_index_file())) {
6305 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CANT_FLUSH_REGISTER_FILE);
6306 goto err;
6307 }
6308
6309 /* We know how many files to delete. Update index file. */
6310
2/4
✓ Branch 0 taken 24030 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24030 times.
24031 if ((error = remove_logs_from_index(&log_info, need_update_threads))) {
6311 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CANT_UPDATE_INDEX_FILE);
6312 goto err;
6313 }
6314
6315 // Update gtid_state->lost_gtids
6316
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 23823 times.
24030 if (!is_relay_log) {
6317
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 global_sid_lock->wrlock();
6318
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 error = init_gtid_sets(
6319 207 nullptr, const_cast<Gtid_set *>(gtid_state->get_lost_gtids()),
6320 opt_source_verify_checksum, false /*false=don't need lock*/,
6321 nullptr /*trx_parser*/, nullptr /*partial_trx*/);
6322
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 global_sid_lock->unlock();
6323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207 if (error) goto err;
6324 }
6325
6326
2/6
✓ Branch 0 taken 24031 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24031 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
24030 DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", DBUG_SUICIDE(););
6327
6328 24031 err:
6329
6330 24033 int error_index = 0, close_error_index = 0;
6331 /* Read each entry from purge_index_file and delete the file. */
6332
5/8
✓ Branch 0 taken 24031 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 24030 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24030 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24033 times.
48064 if (!error && is_inited_purge_index_file() &&
6333
2/4
✓ Branch 0 taken 24031 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24031 times.
24030 (error_index = purge_index_entry(thd, decrease_log_space,
6334 false /*need_lock_index=false*/)))
6335 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_FAILED_TO_PURGE_LOG);
6336
6337
1/2
✓ Branch 0 taken 24033 times.
✗ Branch 1 not taken.
24033 close_error_index = close_purge_index_file();
6338
6339
2/6
✓ Branch 0 taken 24033 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24033 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
24033 DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index",
6340 DBUG_SUICIDE(););
6341
6342
1/2
✓ Branch 0 taken 24033 times.
✗ Branch 1 not taken.
24033 count_binlog_space(false);
6343
3/4
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 23922 times.
✓ Branch 2 taken 111 times.
✗ Branch 3 not taken.
24033 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
6344
6345 /*
6346 Error codes from purge logs take precedence.
6347 Then error codes from purging the index entry.
6348 Finally, error codes from closing the purge index file.
6349 */
6350
3/4
✓ Branch 0 taken 24031 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24031 times.
24033 error = error ? error : (error_index ? error_index : close_error_index);
6351
6352 24033 return error;
6353 24033 }
6354
6355 79078 int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name) {
6356 79078 int error = 0;
6357
1/2
✓ Branch 0 taken 79078 times.
✗ Branch 1 not taken.
79078 DBUG_TRACE;
6358 158156 if (fn_format(
6359
1/2
✓ Branch 0 taken 79078 times.
✗ Branch 1 not taken.
79078 purge_index_file_name, base_file_name, mysql_data_home, ".~rec~",
6360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79078 times.
79078 MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_REPLACE_EXT)) == nullptr) {
6361 error = 1;
6362 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_SET_PURGE_INDEX_FILE_NAME);
6363 }
6364 79078 return error;
6365 79078 }
6366
6367 181972 int MYSQL_BIN_LOG::open_purge_index_file(bool destroy) {
6368 181972 int error = 0;
6369 181972 File file = -1;
6370
6371
1/2
✓ Branch 0 taken 181972 times.
✗ Branch 1 not taken.
181972 DBUG_TRACE;
6372
6373
3/4
✓ Branch 0 taken 102894 times.
✓ Branch 1 taken 79078 times.
✓ Branch 2 taken 102894 times.
✗ Branch 3 not taken.
181972 if (destroy) close_purge_index_file();
6374
6375
1/2
✓ Branch 0 taken 181972 times.
✗ Branch 1 not taken.
181972 if (!my_b_inited(&purge_index_file)) {
6376 181972 myf flags = MY_WME | MY_NABP | MY_WAIT_IF_FULL;
6377
2/2
✓ Branch 0 taken 129345 times.
✓ Branch 1 taken 52627 times.
181972 if (is_relay_log) flags = flags | MY_REPORT_WAITING_IF_FULL;
6378
6379
1/2
✓ Branch 0 taken 181972 times.
✗ Branch 1 not taken.
181972 if ((file = my_open(purge_index_file_name, O_RDWR | O_CREAT, MYF(MY_WME))) <
6380
2/4
✓ Branch 0 taken 181972 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 181972 times.
363944 0 ||
6381
4/6
✓ Branch 0 taken 102894 times.
✓ Branch 1 taken 79078 times.
✓ Branch 2 taken 181972 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 181972 times.
181972 init_io_cache(&purge_index_file, file, IO_SIZE,
6382 (destroy ? WRITE_CACHE : READ_CACHE), 0, false, flags)) {
6383 error = 1;
6384 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_OPEN_REGISTER_FILE);
6385 }
6386 }
6387 181972 return error;
6388 181972 }
6389
6390 284862 int MYSQL_BIN_LOG::close_purge_index_file() {
6391 284862 int error = 0;
6392
6393
1/2
✓ Branch 0 taken 284862 times.
✗ Branch 1 not taken.
284862 DBUG_TRACE;
6394
6395
2/2
✓ Branch 0 taken 181967 times.
✓ Branch 1 taken 102895 times.
284862 if (my_b_inited(&purge_index_file)) {
6396
1/2
✓ Branch 0 taken 181967 times.
✗ Branch 1 not taken.
181967 end_io_cache(&purge_index_file);
6397
1/2
✓ Branch 0 taken 181967 times.
✗ Branch 1 not taken.
181967 error = my_close(purge_index_file.file, MYF(0));
6398 }
6399
1/2
✓ Branch 0 taken 284862 times.
✗ Branch 1 not taken.
284862 my_delete(purge_index_file_name, MYF(0));
6400 284862 new (&purge_index_file) IO_CACHE();
6401
6402 284862 return error;
6403 284862 }
6404
6405 24033 bool MYSQL_BIN_LOG::is_inited_purge_index_file() {
6406
1/2
✓ Branch 0 taken 24033 times.
✗ Branch 1 not taken.
24033 DBUG_TRACE;
6407 48065 return my_b_inited(&purge_index_file);
6408 24033 }
6409
6410 102894 int MYSQL_BIN_LOG::sync_purge_index_file() {
6411 102894 int error = 0;
6412
1/2
✓ Branch 0 taken 102894 times.
✗ Branch 1 not taken.
102894 DBUG_TRACE;
6413
6414
5/6
✓ Branch 0 taken 102894 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102893 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 102893 times.
205787 if ((error = flush_io_cache(&purge_index_file)) ||
6415
2/4
✓ Branch 0 taken 102893 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102893 times.
102893 (error = my_sync(purge_index_file.file, MYF(MY_WME))))
6416 1 return error;
6417
6418 102893 return error;
6419 102894 }
6420
6421 93895 int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry) {
6422 93895 int error = 0;
6423
1/2
✓ Branch 0 taken 93895 times.
✗ Branch 1 not taken.
93895 DBUG_TRACE;
6424
6425
1/2
✓ Branch 0 taken 93895 times.
✗ Branch 1 not taken.
93895 if ((error = my_b_write(&purge_index_file, (const uchar *)entry,
6426
2/4
✓ Branch 0 taken 93895 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 93895 times.
187790 strlen(entry))) ||
6427
2/4
✓ Branch 0 taken 93895 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 93895 times.
93895 (error = my_b_write(&purge_index_file, (const uchar *)"\n", 1)))
6428 return error;
6429
6430 93895 return error;
6431 93895 }
6432
6433 78863 int MYSQL_BIN_LOG::register_create_index_entry(const char *entry) {
6434
1/2
✓ Branch 0 taken 78863 times.
✗ Branch 1 not taken.
78863 DBUG_TRACE;
6435
1/2
✓ Branch 0 taken 78863 times.
✗ Branch 1 not taken.
157726 return register_purge_index_entry(entry);
6436 78863 }
6437
6438 103110 int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
6439 bool need_lock_index) {
6440 MY_STAT s;
6441 103110 int error = 0;
6442 103110 LOG_INFO log_info;
6443 103111 LOG_INFO check_log_info;
6444
6445
1/2
✓ Branch 0 taken 103111 times.
✗ Branch 1 not taken.
103111 DBUG_TRACE;
6446
6447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103111 times.
103111 assert(my_b_inited(&purge_index_file));
6448
6449 103110 if ((error =
6450
2/4
✓ Branch 0 taken 103110 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103110 times.
103111 reinit_io_cache(&purge_index_file, READ_CACHE, 0, false, false))) {
6451 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_REINIT_REGISTER_FILE);
6452 goto err;
6453 }
6454
6455 for (;;) {
6456 size_t length;
6457
6458
1/2
✓ Branch 0 taken 118151 times.
✗ Branch 1 not taken.
118150 if ((length = my_b_gets(&purge_index_file, log_info.log_file_name,
6459
2/2
✓ Branch 0 taken 103111 times.
✓ Branch 1 taken 15040 times.
118151 FN_REFLEN)) <= 1) {
6460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103111 times.
103111 if (purge_index_file.error) {
6461 error = purge_index_file.error;
6462 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_READ_REGISTER_FILE, error);
6463 goto err;
6464 }
6465
6466 /* Reached EOF */
6467 103111 break;
6468 }
6469
6470 /* Get rid of the trailing '\n' */
6471 15040 log_info.log_file_name[length - 1] = 0;
6472
6473
3/4
✓ Branch 0 taken 15040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 15036 times.
15040 if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &s, MYF(0))) {
6474
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (my_errno() == ENOENT) {
6475 /*
6476 It's not fatal if we can't stat a log file that does not exist;
6477 If we could not stat, we won't delete.
6478 */
6479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (thd) {
6480 push_warning_printf(
6481 thd, Sql_condition::SL_WARNING, ER_LOG_PURGE_NO_FILE,
6482 ER_THD(thd, ER_LOG_PURGE_NO_FILE), log_info.log_file_name);
6483 }
6484
8/16
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 4 times.
✗ Branch 15 not taken.
4 LogErr(INFORMATION_LEVEL, ER_CANT_STAT_FILE, log_info.log_file_name);
6485
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 set_my_errno(0);
6486 } else {
6487 /*
6488 Other than ENOENT are fatal
6489 */
6490 if (thd) {
6491 push_warning_printf(thd, Sql_condition::SL_WARNING,
6492 ER_BINLOG_PURGE_FATAL_ERR,
6493 "a problem with getting info on being purged %s; "
6494 "consider examining correspondence "
6495 "of your binlog index file "
6496 "to the actual binlog files",
6497 log_info.log_file_name);
6498 } else {
6499 LogErr(INFORMATION_LEVEL,
6500 ER_BINLOG_CANT_DELETE_LOG_FILE_DOES_INDEX_MATCH_FILES,
6501 log_info.log_file_name);
6502 }
6503 error = LOG_INFO_FATAL;
6504 goto err;
6505 }
6506 } else {
6507
2/4
✓ Branch 0 taken 15036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15036 times.
✗ Branch 3 not taken.
15036 if ((error = find_log_pos(&check_log_info, log_info.log_file_name,
6508 need_lock_index))) {
6509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15036 times.
15036 if (error != LOG_INFO_EOF) {
6510 if (thd) {
6511 push_warning_printf(thd, Sql_condition::SL_WARNING,
6512 ER_BINLOG_PURGE_FATAL_ERR,
6513 "a problem with deleting %s and "
6514 "reading the binlog index file",
6515 log_info.log_file_name);
6516 } else {
6517 LogErr(INFORMATION_LEVEL,
6518 ER_BINLOG_CANT_DELETE_FILE_AND_READ_BINLOG_INDEX,
6519 log_info.log_file_name);
6520 }
6521 goto err;
6522 }
6523
6524 15036 error = 0;
6525
1/2
✓ Branch 0 taken 15036 times.
✗ Branch 1 not taken.
15036 if (!need_lock_index) {
6526 /*
6527 This is to avoid triggering an error in NDB.
6528
6529 @todo: This is weird, what does NDB errors have to do with
6530 need_lock_index? Explain better or refactor /Sven
6531 */
6532
2/4
✓ Branch 0 taken 15036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15036 times.
✗ Branch 3 not taken.
15036 ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
6533 }
6534
6535
3/8
✓ Branch 0 taken 15036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15036 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15036 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
15036 DBUG_PRINT("info", ("purging %s", log_info.log_file_name));
6536
2/4
✓ Branch 0 taken 15036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15036 times.
✗ Branch 3 not taken.
15036 if (!mysql_file_delete(key_file_binlog, log_info.log_file_name,
6537 MYF(0))) {
6538
6/10
✓ Branch 0 taken 15036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 15035 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
15036 DBUG_EXECUTE_IF("wait_in_purge_index_entry", {
6539 const char action[] =
6540 "now SIGNAL in_purge_index_entry WAIT_FOR go_ahead_sql";
6541 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
6542 DBUG_SET("-d,wait_in_purge_index_entry");
6543 };);
6544
6545
2/2
✓ Branch 0 taken 14738 times.
✓ Branch 1 taken 298 times.
15036 if (decrease_log_space) *decrease_log_space -= s.st_size;
6546 } else {
6547 if (my_errno() == ENOENT) {
6548 if (thd) {
6549 push_warning_printf(
6550 thd, Sql_condition::SL_WARNING, ER_LOG_PURGE_NO_FILE,
6551 ER_THD(thd, ER_LOG_PURGE_NO_FILE), log_info.log_file_name);
6552 }
6553 LogErr(INFORMATION_LEVEL, ER_BINLOG_CANT_DELETE_FILE,
6554 log_info.log_file_name);
6555 set_my_errno(0);
6556 } else {
6557 if (thd) {
6558 push_warning_printf(thd, Sql_condition::SL_WARNING,
6559 ER_BINLOG_PURGE_FATAL_ERR,
6560 "a problem with deleting %s; "
6561 "consider examining correspondence "
6562 "of your binlog index file "
6563 "to the actual binlog files",
6564 log_info.log_file_name);
6565 } else {
6566 LogErr(INFORMATION_LEVEL,
6567 ER_BINLOG_CANT_DELETE_LOG_FILE_DOES_INDEX_MATCH_FILES,
6568 log_info.log_file_name);
6569 }
6570 if (my_errno() == EMFILE) {
6571 DBUG_PRINT("info", ("my_errno: %d, set ret = LOG_INFO_EMFILE",
6572 my_errno()));
6573 error = LOG_INFO_EMFILE;
6574 goto err;
6575 }
6576 error = LOG_INFO_FATAL;
6577 goto err;
6578 }
6579 }
6580 }
6581 }
6582 15040 }
6583
6584 103111 err:
6585 103111 return error;
6586 103111 }
6587
6588 /**
6589 Count a total size of binary logs (except the active one) to the variable
6590 binlog_space_total.
6591
6592 @param need_lock_index If true, this function acquires LOCK_index;
6593 otherwise the caller should already have acquired it.
6594
6595 @retval
6596 0 ok
6597 @retval
6598 LOG_INFO_FATAL if any other than ENOENT error from
6599 mysql_file_stat() or mysql_file_delete()
6600 LOG_INFO_EOF End of log-index-file found
6601 LOG_INFO_IO Got IO error while reading log-index-file
6602 */
6603
6604 53243 int MYSQL_BIN_LOG::count_binlog_space(bool need_lock_index) {
6605
1/2
✓ Branch 0 taken 53243 times.
✗ Branch 1 not taken.
53243 DBUG_ENTER("count_binlog_space");
6606
3/4
✓ Branch 0 taken 43803 times.
✓ Branch 1 taken 9440 times.
✓ Branch 2 taken 43803 times.
✗ Branch 3 not taken.
53243 if (is_relay_log) DBUG_RETURN(0);
6607
6608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9440 times.
9440 if (need_lock_index)
6609 mysql_mutex_lock(&LOCK_index);
6610 else
6611 mysql_mutex_assert_owner(&LOCK_index);
6612
6613 int error;
6614 9440 LOG_INFO log_info;
6615 9440 binlog_space_total = 0;
6616
3/4
✓ Branch 0 taken 9440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 9433 times.
9440 if ((error = find_log_pos(&log_info, NullS, false /*need_lock_index=false*/)))
6617 7 goto done;
6618
6619 MY_STAT stat_area;
6620
3/4
✓ Branch 0 taken 10123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 690 times.
✓ Branch 3 taken 9433 times.
10123 while (!(is_active(log_info.log_file_name))) {
6621
2/4
✓ Branch 0 taken 690 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 690 times.
690 if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area,
6622 MYF(0))) {
6623 if (my_errno() == ENOENT) {
6624 /*
6625 It's not fatal if we can't stat a log file that does not exist.
6626 */
6627 set_my_errno(0);
6628 } else {
6629 error = LOG_INFO_FATAL;
6630 goto done;
6631 }
6632 } else {
6633 690 binlog_space_total += stat_area.st_size;
6634 }
6635
2/4
✓ Branch 0 taken 690 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 690 times.
690 if (find_next_log(&log_info, false /*need_lock_index=false*/)) break;
6636 }
6637
6638 9433 error = 0;
6639
6640 9440 done:
6641
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9440 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
9440 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
6642
1/2
✓ Branch 0 taken 9440 times.
✗ Branch 1 not taken.
9440 DBUG_RETURN(error);
6643 }
6644
6645 /**
6646 Purge old logs so that we have a total size lower than binlog_space_limit.
6647
6648 @param need_lock_index If true, this function acquires LOCK_index;
6649 otherwise the caller should already have acquired it.
6650
6651 @note
6652 If any of the logs before the deleted one is in use,
6653 only purge logs up to this one.
6654
6655 @retval
6656 0 ok
6657 @retval
6658 LOG_INFO_FATAL if any other than ENOENT error from
6659 mysql_file_stat() or mysql_file_delete()
6660 LOG_INFO_EOF End of log-index-file found
6661 LOG_INFO_IO Got IO error while reading log-index-file
6662 */
6663
6664 68 int MYSQL_BIN_LOG::purge_logs_by_size(bool need_lock_index) {
6665
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 DBUG_ENTER("purge_logs_by_size");
6666
6667
2/6
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
68 if (is_relay_log || !binlog_space_limit) DBUG_RETURN(0);
6668
6669
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 if (need_lock_index)
6670
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 mysql_mutex_lock(&LOCK_index);
6671 else
6672 mysql_mutex_assert_owner(&LOCK_index);
6673
6674 68 int error = 0;
6675 68 LOG_INFO log_info;
6676 68 const auto binlog_pos = m_binlog_file->position();
6677
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 count_binlog_space(false);
6678
6679
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 6 times.
68 if (!binlog_space_total ||
6680
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 27 times.
62 binlog_space_total + binlog_pos <= binlog_space_limit)
6681 41 goto done;
6682
6683
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 if ((error = find_log_pos(&log_info, NullS, false /*need_lock_index=false*/)))
6684 goto done;
6685
6686 MY_STAT stat_area;
6687 char to_log[FN_REFLEN];
6688 27 to_log[0] = 0;
6689
3/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 9 times.
60 while (!is_active(log_info.log_file_name)) {
6690
2/4
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 51 times.
51 if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area,
6691 MYF(0))) {
6692 if (my_errno() == ENOENT) {
6693 /*
6694 It's not fatal if we can't stat a log file that does not exist.
6695 */
6696 set_my_errno(0);
6697 } else {
6698 /*
6699 Other than ENOENT are fatal
6700 */
6701 THD *thd = current_thd;
6702 if (thd) {
6703 push_warning_printf(thd, Sql_condition::SL_WARNING,
6704 ER_BINLOG_PURGE_FATAL_ERR,
6705 "a problem with getting info on being purged %s; "
6706 "consider examining correspondence "
6707 "of your binlog index file "
6708 "to the actual binlog files",
6709 log_info.log_file_name);
6710 } else {
6711 LogErr(INFORMATION_LEVEL, ER_CANT_STAT_FILE, log_info.log_file_name);
6712 }
6713 error = LOG_INFO_FATAL;
6714 goto done;
6715 }
6716 }
6717 /* check if a total size of binary logs is bigger than binlog_space_limit
6718 if yes check if it is in use, if not in use then add
6719 it in the list of binary log files to be purged.
6720 */
6721
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 18 times.
51 else if (binlog_space_total + binlog_pos > binlog_space_limit) {
6722
2/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
33 if ((log_in_use(log_info.log_file_name))) break;
6723
3/8
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
33 DBUG_PRINT("info", ("purge_logs_by_size binlog_space_total=%llu "
6724 "binlog_pos=%llu sum=%llu\n",
6725 binlog_space_total, binlog_pos,
6726 binlog_space_total + binlog_pos));
6727
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (binlog_space_total >= (ulonglong)stat_area.st_size)
6728 33 binlog_space_total -= stat_area.st_size;
6729 else
6730 break;
6731
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 strmake(to_log, log_info.log_file_name,
6732 sizeof(log_info.log_file_name) - 1);
6733 } else
6734 18 break;
6735
2/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
33 if (find_next_log(&log_info, false /*need_lock_index=false*/)) break;
6736 }
6737
6738
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 error = (to_log[0] ? purge_logs(to_log, true, false /*need_lock_index=false*/,
6739 true /*need_update_threads=true*/, NULL, true)
6740 : 0);
6741
6742 68 done:
6743
2/4
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
68 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
6744
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 DBUG_RETURN(error);
6745 }
6746
6747 /**
6748 Remove all logs before the given file date from disk and from the
6749 index file.
6750
6751 @param purge_time Delete all log files before given date.
6752 @param auto_purge True if this is an automatic purge.
6753
6754 @note
6755 If any of the logs before the deleted one is in use,
6756 only purge logs up to this one.
6757
6758 @retval
6759 0 ok
6760 @retval
6761 LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
6762 LOG_INFO_FATAL if any other than ENOENT error from
6763 mysql_file_stat() or mysql_file_delete()
6764 */
6765
6766 15947 int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time, bool auto_purge) {
6767 int error;
6768 15947 int no_of_threads_locking_log = 0, no_of_log_files_purged = 0;
6769 15947 bool log_is_active = false, log_is_in_use = false;
6770 char to_log[FN_REFLEN], copy_log_in_use[FN_REFLEN];
6771 15947 LOG_INFO log_info;
6772 MY_STAT stat_area;
6773
1/2
✓ Branch 0 taken 15947 times.
✗ Branch 1 not taken.
15947 THD *thd = current_thd;
6774
6775
1/2
✓ Branch 0 taken 15947 times.
✗ Branch 1 not taken.
15947 DBUG_TRACE;
6776
6777
1/2
✓ Branch 0 taken 15947 times.
✗ Branch 1 not taken.
15947 mysql_mutex_lock(&LOCK_index);
6778 15947 to_log[0] = 0;
6779
6780
2/4
✓ Branch 0 taken 15947 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15947 times.
15947 if ((error = find_log_pos(&log_info, NullS, false /*need_lock_index=false*/)))
6781 goto err;
6782
6783
3/4
✓ Branch 0 taken 16086 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11837 times.
✓ Branch 3 taken 4249 times.
16086 while (!(log_is_active = is_active(log_info.log_file_name))) {
6784
2/4
✓ Branch 0 taken 11837 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11837 times.
11837 if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area,
6785 MYF(0))) {
6786 if (my_errno() == ENOENT) {
6787 /*
6788 It's not fatal if we can't stat a log file that does not exist.
6789 */
6790 set_my_errno(0);
6791 } else {
6792 /*
6793 Other than ENOENT are fatal
6794 */
6795 if (thd) {
6796 push_warning_printf(thd, Sql_condition::SL_WARNING,
6797 ER_BINLOG_PURGE_FATAL_ERR,
6798 "a problem with getting info on being purged %s; "
6799 "consider examining correspondence "
6800 "of your binlog index file "
6801 "to the actual binlog files",
6802 log_info.log_file_name);
6803 } else {
6804 LogErr(INFORMATION_LEVEL, ER_BINLOG_FAILED_TO_DELETE_LOG_FILE,
6805 log_info.log_file_name);
6806 }
6807 error = LOG_INFO_FATAL;
6808 goto err;
6809 }
6810 }
6811 /* check if the binary log file is older than the purge_time
6812 if yes check if it is in use, if not in use then add
6813 it in the list of binary log files to be purged.
6814 */
6815
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 11698 times.
11837 else if (stat_area.st_mtime < purge_time) {
6816
2/4
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
139 if ((no_of_threads_locking_log = log_in_use(log_info.log_file_name))) {
6817 if (!auto_purge) {
6818 log_is_in_use = true;
6819 strcpy(copy_log_in_use, log_info.log_file_name);
6820 }
6821 break;
6822 }
6823
1/2
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
139 strmake(to_log, log_info.log_file_name,
6824 sizeof(log_info.log_file_name) - 1);
6825 139 no_of_log_files_purged++;
6826 } else
6827 11698 break;
6828
2/4
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
139 if (find_next_log(&log_info, false /*need_lock_index=false*/)) break;
6829 }
6830
6831
2/2
✓ Branch 0 taken 4249 times.
✓ Branch 1 taken 11698 times.
15947 if (log_is_active) {
6832
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4235 times.
4249 if (!auto_purge)
6833
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 push_warning_printf(
6834 thd, Sql_condition::SL_WARNING, ER_WARN_PURGE_LOG_IS_ACTIVE,
6835 ER_THD(thd, ER_WARN_PURGE_LOG_IS_ACTIVE), log_info.log_file_name);
6836 }
6837
6838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15947 times.
15947 if (log_is_in_use) {
6839 int no_of_log_files_to_purge = no_of_log_files_purged + 1;
6840 while (strcmp(log_file_name, log_info.log_file_name)) {
6841 if (mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area,
6842 MYF(0))) {
6843 if (stat_area.st_mtime < purge_time)
6844 no_of_log_files_to_purge++;
6845 else
6846 break;
6847 }
6848 if (find_next_log(&log_info, false /*need_lock_index=false*/)) {
6849 no_of_log_files_to_purge++;
6850 break;
6851 }
6852 }
6853
6854 push_warning_printf(thd, Sql_condition::SL_WARNING,
6855 ER_WARN_PURGE_LOG_IN_USE,
6856 ER_THD(thd, ER_WARN_PURGE_LOG_IN_USE), copy_log_in_use,
6857 no_of_threads_locking_log, no_of_log_files_purged,
6858 no_of_log_files_to_purge);
6859 }
6860
6861
3/4
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 15876 times.
✓ Branch 2 taken 71 times.
✗ Branch 3 not taken.
15947 error = (to_log[0] ? purge_logs(to_log, true, false /*need_lock_index=false*/,
6862 true /*need_update_threads=true*/,
6863 (ulonglong *)nullptr, auto_purge)
6864 : 0);
6865
6866 15947 err:
6867
1/2
✓ Branch 0 taken 15947 times.
✗ Branch 1 not taken.
15947 mysql_mutex_unlock(&LOCK_index);
6868 15947 return error;
6869 15947 }
6870
6871 /**
6872 Create a new log file name.
6873
6874 @param[out] buf Buffer allocated with at least FN_REFLEN bytes where
6875 new name is stored.
6876 @param log_ident Identity of the binary/relay log.
6877
6878 @note
6879 If file name will be longer then FN_REFLEN it will be truncated
6880 */
6881
6882 16631 void MYSQL_BIN_LOG::make_log_name(char *buf, const char *log_ident) {
6883 16631 size_t dir_len = dirname_length(log_file_name);
6884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16631 times.
16631 if (dir_len >= FN_REFLEN) dir_len = FN_REFLEN - 1;
6885 16631 my_stpnmov(buf, log_file_name, dir_len);
6886 16631 strmake(buf + dir_len, log_ident, FN_REFLEN - dir_len - 1);
6887 16631 }
6888
6889 /**
6890 Check if we are writing/reading to the given log file.
6891 */
6892
6893 4011746 bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg) {
6894 4011746 return !compare_log_name(log_file_name, log_file_name_arg);
6895 }
6896
6897 2039489 void MYSQL_BIN_LOG::inc_prep_xids(THD *thd) {
6898
1/2
✓ Branch 0 taken 2039489 times.
✗ Branch 1 not taken.
2039489 DBUG_TRACE;
6899 #ifndef NDEBUG
6900 2039489 int result = ++m_atomic_prep_xids;
6901
5/8
✓ Branch 0 taken 2039489 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2039489 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 82 times.
✓ Branch 5 taken 2039407 times.
✓ Branch 6 taken 82 times.
✗ Branch 7 not taken.
2039489 DBUG_PRINT("debug", ("m_atomic_prep_xids: %d", result));
6902 #else
6903 m_atomic_prep_xids++;
6904 #endif
6905 2039489 thd->get_transaction()->m_flags.xid_written = true;
6906 2039489 }
6907
6908 2039360 void MYSQL_BIN_LOG::dec_prep_xids(THD *thd) {
6909
1/2
✓ Branch 0 taken 2039360 times.
✗ Branch 1 not taken.
2039360 DBUG_TRACE;
6910 2039360 int32 result = --m_atomic_prep_xids;
6911
5/8
✓ Branch 0 taken 2039360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2039360 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 80 times.
✓ Branch 5 taken 2039280 times.
✓ Branch 6 taken 80 times.
✗ Branch 7 not taken.
2039360 DBUG_PRINT("debug", ("m_atomic_prep_xids: %d", result));
6912 2039360 thd->get_transaction()->m_flags.xid_written = false;
6913
2/2
✓ Branch 0 taken 1914393 times.
✓ Branch 1 taken 124967 times.
2039360 if (result == 0) {
6914
1/2
✓ Branch 0 taken 1914393 times.
✗ Branch 1 not taken.
1914393 mysql_mutex_lock(&LOCK_xids);
6915
1/2
✓ Branch 0 taken 1914393 times.
✗ Branch 1 not taken.
1914393 mysql_cond_signal(&m_prep_xids_cond);
6916
1/2
✓ Branch 0 taken 1914393 times.
✗ Branch 1 not taken.
1914393 mysql_mutex_unlock(&LOCK_xids);
6917 }
6918 2039360 }
6919
6920 /*
6921 Wrappers around new_file_impl to avoid using argument
6922 to control locking. The argument 1) less readable 2) breaks
6923 incapsulation 3) allows external access to the class without
6924 a lock (which is not possible with private new_file_without_locking
6925 method).
6926
6927 @retval
6928 nonzero - error
6929
6930 */
6931
6932 int MYSQL_BIN_LOG::new_file(
6933 Format_description_log_event *extra_description_event) {
6934 return new_file_impl(true /*need_lock_log=true*/, extra_description_event);
6935 }
6936
6937 /*
6938 @retval
6939 nonzero - error
6940 */
6941 31818 int MYSQL_BIN_LOG::new_file_without_locking(
6942 Format_description_log_event *extra_description_event) {
6943 31818 return new_file_impl(false /*need_lock_log=false*/, extra_description_event);
6944 }
6945
6946 /**
6947 Start writing to a new log file or reopen the old file.
6948
6949 @param need_lock_log If true, this function acquires LOCK_log;
6950 otherwise the caller should already have acquired it.
6951
6952 @param extra_description_event The master's FDE to be written by the I/O
6953 thread while creating a new relay log file. This should be NULL for
6954 binary log files.
6955
6956 @retval 0 success
6957 @retval nonzero - error
6958
6959 @note The new file name is stored last in the index file
6960 */
6961 31818 int MYSQL_BIN_LOG::new_file_impl(
6962 bool need_lock_log, Format_description_log_event *extra_description_event) {
6963 31818 int error = 0;
6964 31818 bool close_on_error = false;
6965 31818 char new_name[FN_REFLEN], *new_name_ptr = nullptr, *old_name, *file_to_open;
6966 31818 const size_t ERR_CLOSE_MSG_LEN = 1024;
6967 char close_on_error_msg[ERR_CLOSE_MSG_LEN];
6968 31818 memset(close_on_error_msg, 0, sizeof close_on_error_msg);
6969
6970
1/2
✓ Branch 0 taken 31818 times.
✗ Branch 1 not taken.
31818 DBUG_TRACE;
6971
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 31789 times.
31818 if (!is_open()) {
6972
3/8
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
29 DBUG_PRINT("info", ("log is closed"));
6973 29 return error;
6974 }
6975
6976
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31789 times.
31789 if (need_lock_log)
6977 mysql_mutex_lock(&LOCK_log);
6978 else
6979 mysql_mutex_assert_owner(&LOCK_log);
6980
6/10
✓ Branch 0 taken 31789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 31780 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
31789 DBUG_EXECUTE_IF("semi_sync_3-way_deadlock",
6981 DEBUG_SYNC(current_thd, "before_rotate_binlog"););
6982
1/2
✓ Branch 0 taken 31789 times.
✗ Branch 1 not taken.
31789 mysql_mutex_lock(&LOCK_xids);
6983 /*
6984 We need to ensure that the number of prepared XIDs are 0.
6985
6986 If m_atomic_prep_xids is not zero:
6987 - We wait for storage engine commit, hence decrease m_atomic_prep_xids
6988 - We keep the LOCK_log to block new transactions from being
6989 written to the binary log.
6990 */
6991
2/2
✓ Branch 0 taken 1302 times.
✓ Branch 1 taken 31789 times.
33091 while (get_prep_xids() > 0) {
6992
1/2
✓ Branch 0 taken 1302 times.
✗ Branch 1 not taken.
1302 mysql_cond_wait(&m_prep_xids_cond, &LOCK_xids);
6993 }
6994
1/2
✓ Branch 0 taken 31789 times.
✗ Branch 1 not taken.
31789 mysql_mutex_unlock(&LOCK_xids);
6995
6996
1/2
✓ Branch 0 taken 31789 times.
✗ Branch 1 not taken.
31789 mysql_mutex_lock(&LOCK_index);
6997
6998 mysql_mutex_assert_owner(&LOCK_log);
6999 mysql_mutex_assert_owner(&LOCK_index);
7000
7001
3/6
✓ Branch 0 taken 31789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31789 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31789 times.
63578 if (DBUG_EVALUATE_IF("expire_logs_always", 0, 1) &&
7002
2/4
✓ Branch 0 taken 31789 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31789 times.
31789 (error = ha_flush_logs())) {
7003 goto end;
7004 }
7005
7006
2/2
✓ Branch 0 taken 7977 times.
✓ Branch 1 taken 23812 times.
31789 if (!is_relay_log) {
7007 /* Save set of GTIDs of the last binlog into table on binlog rotation */
7008
3/4
✓ Branch 0 taken 7977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 7974 times.
7977 if ((error = gtid_state->save_gtids_of_last_binlog_into_table())) {
7009
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (error == ER_RPL_GTID_TABLE_CANNOT_OPEN) {
7010 3 close_on_error =
7011 3 m_binlog_file->get_real_file_size() >=
7012
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 static_cast<my_off_t>(max_size) ||
7013
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 DBUG_EVALUATE_IF("simulate_max_binlog_size", true, false);
7014
7015
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (!close_on_error) {
7016
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_UNABLE_TO_ROTATE_GTID_TABLE_READONLY,
7017 "Current binlog file was flushed to disk and will be kept in "
7018 "use.");
7019 } else {
7020 snprintf(close_on_error_msg, sizeof close_on_error_msg,
7021 ER_THD(current_thd, ER_RPL_GTID_TABLE_CANNOT_OPEN), "mysql",
7022 "gtid_executed");
7023
7024 if (binlog_error_action != ABORT_SERVER)
7025 LogErr(WARNING_LEVEL,
7026 ER_BINLOG_UNABLE_TO_ROTATE_GTID_TABLE_READONLY,
7027 "Binary logging going to be disabled.");
7028 }
7029
7030
2/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3 DBUG_EXECUTE_IF("gtid_executed_readonly",
7031 { DBUG_SET("-d,gtid_executed_readonly"); });
7032
2/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3 DBUG_EXECUTE_IF("simulate_max_binlog_size",
7033 { DBUG_SET("-d,simulate_max_binlog_size"); });
7034 } else {
7035 close_on_error = true;
7036 snprintf(close_on_error_msg, sizeof close_on_error_msg, "%s",
7037 ER_THD(current_thd, ER_OOM_SAVE_GTIDS));
7038 }
7039 3 goto end;
7040 }
7041 }
7042
7043 /*
7044 If user hasn't specified an extension, generate a new log name
7045 We have to do this here and not in open as we want to store the
7046 new file name in the current binary log file.
7047 */
7048 31786 new_name_ptr = new_name;
7049
3/4
✓ Branch 0 taken 31785 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 31770 times.
31786 if ((error = generate_new_name(new_name, name))) {
7050 // Use the old name if generation of new name fails.
7051 15 strcpy(new_name, name);
7052 15 close_on_error = true;
7053 45 snprintf(close_on_error_msg, sizeof close_on_error_msg,
7054
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 ER_THD(current_thd, ER_NO_UNIQUE_LOGFILE), name);
7055
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (strlen(close_on_error_msg)) {
7056 15 close_on_error_msg[strlen(close_on_error_msg) - 1] = '\0';
7057 }
7058 15 goto end;
7059 }
7060
7061 /*
7062 Make sure that the log_file is initialized before writing
7063 Rotate_log_event into it.
7064 */
7065
2/2
✓ Branch 0 taken 31770 times.
✓ Branch 1 taken 1 times.
31770 if (m_binlog_file->is_open()) {
7066 /*
7067 We log the whole file name for log file as the user may decide
7068 to change base names at some point.
7069 */
7070
1/2
✓ Branch 0 taken 31770 times.
✗ Branch 1 not taken.
31770 Rotate_log_event r(new_name + dirname_length(new_name), 0, LOG_EVENT_OFFSET,
7071
3/4
✓ Branch 0 taken 23811 times.
✓ Branch 1 taken 7959 times.
✓ Branch 2 taken 31770 times.
✗ Branch 3 not taken.
63540 is_relay_log ? Rotate_log_event::RELAY_LOG : 0);
7072
7073
3/4
✓ Branch 0 taken 31770 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 31765 times.
31770 if (DBUG_EVALUATE_IF("fault_injection_new_file_rotate_event", (error = 1),
7074
4/4
✓ Branch 0 taken 31765 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 31765 times.
63535 false) ||
7075
2/4
✓ Branch 0 taken 31765 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31765 times.
31765 (error = write_event_to_binlog(&r))) {
7076 char errbuf[MYSYS_STRERROR_SIZE];
7077
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 DBUG_EXECUTE_IF("fault_injection_new_file_rotate_event", errno = 2;);
7078 5 close_on_error = true;
7079 20 snprintf(close_on_error_msg, sizeof close_on_error_msg,
7080
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 ER_THD(current_thd, ER_ERROR_ON_WRITE), name, errno,
7081
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 my_strerror(errbuf, sizeof(errbuf), errno));
7082
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 my_printf_error(ER_ERROR_ON_WRITE, ER_THD(current_thd, ER_ERROR_ON_WRITE),
7083
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 MYF(ME_FATALERROR), name, errno,
7084
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 my_strerror(errbuf, sizeof(errbuf), errno));
7085 5 goto end;
7086 }
7087
7088
2/4
✓ Branch 0 taken 31764 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31764 times.
31765 if ((error = m_binlog_file->flush())) {
7089 close_on_error = true;
7090 snprintf(close_on_error_msg, sizeof close_on_error_msg, "%s",
7091 "Either disk is full or file system is read only");
7092 goto end;
7093 }
7094
2/2
✓ Branch 0 taken 31764 times.
✓ Branch 1 taken 5 times.
31769 }
7095
7096
3/6
✓ Branch 0 taken 31765 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31765 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31766 times.
✗ Branch 5 not taken.
31765 DEBUG_SYNC(current_thd, "after_rotate_event_appended");
7097
7098 31766 old_name = name;
7099 31766 name = nullptr; // Don't free name
7100
1/2
✓ Branch 0 taken 31766 times.
✗ Branch 1 not taken.
31766 close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX, false /*need_lock_log=false*/,
7101 false /*need_lock_index=false*/);
7102
7103
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 31746 times.
31766 if (checksum_alg_reset != binary_log::BINLOG_CHECKSUM_ALG_UNDEF) {
7104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 assert(!is_relay_log);
7105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 assert(binlog_checksum_options != checksum_alg_reset);
7106 20 binlog_checksum_options = checksum_alg_reset;
7107 }
7108 /*
7109 Note that at this point, atomic_log_state != LOG_CLOSED
7110 (important for is_open()).
7111 */
7112
7113
3/6
✓ Branch 0 taken 31766 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31766 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31766 times.
✗ Branch 5 not taken.
31766 DEBUG_SYNC(current_thd, "binlog_rotate_between_close_and_open");
7114 /*
7115 new_file() is only used for rotation (in FLUSH LOGS or because size >
7116 max_binlog_size or max_relay_log_size).
7117 If this is a binary log, the Format_description_log_event at the beginning
7118 of the new file should have created=0 (to distinguish with the
7119 Format_description_log_event written at server startup, which should
7120 trigger temp tables deletion on slaves.
7121 */
7122
7123 /* reopen index binlog file, BUG#34582 */
7124 31766 file_to_open = index_file_name;
7125
1/2
✓ Branch 0 taken 31766 times.
✗ Branch 1 not taken.
31766 error = open_index_file(index_file_name, nullptr,
7126 false /*need_lock_index=false*/);
7127
2/2
✓ Branch 0 taken 31763 times.
✓ Branch 1 taken 3 times.
31766 if (!error) {
7128 /* reopen the binary log file. */
7129 31763 file_to_open = new_name_ptr;
7130
1/2
✓ Branch 0 taken 31763 times.
✗ Branch 1 not taken.
31763 error = open_binlog(old_name, new_name_ptr, max_size,
7131 true /*null_created_arg=true*/,
7132 false /*need_lock_index=false*/,
7133 true /*need_sid_lock=true*/, extra_description_event);
7134 }
7135
7136 /* handle reopening errors */
7137
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 31758 times.
31766 if (error) {
7138 char errbuf[MYSYS_STRERROR_SIZE];
7139
4/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 my_printf_error(ER_CANT_OPEN_FILE, ER_THD(current_thd, ER_CANT_OPEN_FILE),
7140 MYF(ME_FATALERROR), file_to_open, error,
7141 my_strerror(errbuf, sizeof(errbuf), error));
7142 8 close_on_error = true;
7143
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
16 snprintf(close_on_error_msg, sizeof close_on_error_msg,
7144
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 ER_THD(current_thd, ER_CANT_OPEN_FILE), file_to_open, error,
7145 my_strerror(errbuf, sizeof(errbuf), error));
7146 }
7147
1/2
✓ Branch 0 taken 31766 times.
✗ Branch 1 not taken.
31766 my_free(old_name);
7148
7149 31789 end:
7150
7151
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31758 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 3 times.
31789 if (error && close_on_error /* rotate, flush or reopen failed */) {
7152 /*
7153 Close whatever was left opened.
7154
7155 We are keeping the behavior as it exists today, ie,
7156 we disable logging and move on (see: BUG#51014).
7157
7158 TODO: as part of WL#1790 consider other approaches:
7159 - kill mysql (safety);
7160 - try multiple locations for opening a log file;
7161 - switch server to protected/readonly mode
7162 - ...
7163 */
7164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (binlog_error_action == ABORT_SERVER) {
7165 char abort_msg[ERR_CLOSE_MSG_LEN + 48];
7166 memset(abort_msg, 0, sizeof abort_msg);
7167 snprintf(abort_msg, sizeof abort_msg,
7168 "%s, while rotating the binlog. "
7169 "Aborting the server",
7170 close_on_error_msg);
7171 exec_binlog_error_action_abort(abort_msg);
7172 } else
7173
9/18
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 28 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 28 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 28 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 28 times.
✗ Branch 17 not taken.
28 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_FOR_LOGGING,
7174 new_name_ptr != nullptr ? new_name_ptr : "new file", errno);
7175
7176
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 close(LOG_CLOSE_INDEX, false /*need_lock_log=false*/,
7177 false /*need_lock_index=false*/);
7178 }
7179
7180
1/2
✓ Branch 0 taken 31789 times.
✗ Branch 1 not taken.
31789 mysql_mutex_unlock(&LOCK_index);
7181
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 31789 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
31789 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
7182
7183
3/6
✓ Branch 0 taken 31789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31789 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31789 times.
✗ Branch 5 not taken.
31789 DEBUG_SYNC(current_thd, "after_disable_binlog");
7184 31789 return error;
7185 31818 }
7186
7187 /**
7188 Called after an event has been written to the relay log by the IO
7189 thread. This flushes and possibly syncs the file (according to the
7190 sync options), rotates the file if it has grown over the limit, and
7191 finally calls signal_update().
7192
7193 @note The caller must hold LOCK_log before invoking this function.
7194
7195 @param mi Master_info for the IO thread.
7196
7197 @retval false success
7198 @retval true error
7199 */
7200 1556617 bool MYSQL_BIN_LOG::after_write_to_relay_log(Master_info *mi) {
7201
1/2
✓ Branch 0 taken 1556617 times.
✗ Branch 1 not taken.
1556617 DBUG_TRACE;
7202
3/8
✓ Branch 0 taken 1556617 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1556617 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1556617 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1556617 DBUG_PRINT("info", ("max_size: %lu", max_size));
7203
7204 // Check pre-conditions
7205 mysql_mutex_assert_owner(&LOCK_log);
7206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1556617 times.
1556617 assert(is_relay_log);
7207
7208 /*
7209 We allow the relay log rotation by relay log size
7210 only if the trx parser is not inside a transaction.
7211 */
7212 1556617 bool can_rotate = mi->transaction_parser.is_not_inside_transaction();
7213
7214 #ifndef NDEBUG
7215 1556617 if (m_binlog_file->get_real_file_size() >
7216
6/8
✓ Branch 0 taken 1556617 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1556617 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18993 times.
✓ Branch 5 taken 1537624 times.
✓ Branch 6 taken 18806 times.
✓ Branch 7 taken 1537811 times.
1575610 DBUG_EVALUATE_IF("rotate_replica_debug_group", 500, max_size) &&
7217
2/2
✓ Branch 0 taken 18806 times.
✓ Branch 1 taken 187 times.
18993 !can_rotate) {
7218
3/8
✓ Branch 0 taken 18806 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18806 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18806 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18806 DBUG_PRINT("info", ("Postponing the rotation by size waiting for "
7219 "the end of the current transaction."));
7220 }
7221 #endif
7222
7223 // Flush and sync
7224
1/2
✓ Branch 0 taken 1556617 times.
✗ Branch 1 not taken.
1556617 bool error = flush_and_sync(false);
7225
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1556611 times.
1556617 if (error) {
7226
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
7227
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 ER_THD(current_thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
7228 "failed to flush event to relay log file");
7229
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 truncate_relaylog_file(mi, atomic_binlog_end_pos);
7230 } else {
7231
2/2
✓ Branch 0 taken 325129 times.
✓ Branch 1 taken 1231482 times.
1556611 if (can_rotate) {
7232
1/2
✓ Branch 0 taken 325129 times.
✗ Branch 1 not taken.
325129 mysql_mutex_lock(&mi->data_lock);
7233 /*
7234 If the last event of the transaction has been flushed, we can add
7235 the GTID (if it is not empty) to the logged set, or else it will
7236 not be available in the Previous GTIDs of the next relay log file
7237 if we are going to rotate the relay log.
7238 */
7239
1/2
✓ Branch 0 taken 325129 times.
✗ Branch 1 not taken.
325129 const Gtid *last_gtid_queued = mi->get_queueing_trx_gtid();
7240
2/2
✓ Branch 0 taken 59087 times.
✓ Branch 1 taken 266042 times.
325129 if (!last_gtid_queued->is_empty()) {
7241
1/2
✓ Branch 0 taken 59087 times.
✗ Branch 1 not taken.
59087 mi->rli->get_sid_lock()->rdlock();
7242
6/10
✓ Branch 0 taken 59087 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 59081 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
59087 DBUG_SIGNAL_WAIT_FOR(current_thd, "updating_received_transaction_set",
7243 "reached_updating_received_transaction_set",
7244 "continue_updating_received_transaction_set");
7245 59087 mi->rli->add_logged_gtid(last_gtid_queued->sidno,
7246
1/2
✓ Branch 0 taken 59087 times.
✗ Branch 1 not taken.
59087 last_gtid_queued->gno);
7247
1/2
✓ Branch 0 taken 59087 times.
✗ Branch 1 not taken.
59087 mi->rli->get_sid_lock()->unlock();
7248 }
7249
7250
3/4
✓ Branch 0 taken 325129 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 282589 times.
✓ Branch 3 taken 42540 times.
325129 if (mi->is_queueing_trx()) {
7251
1/2
✓ Branch 0 taken 282589 times.
✗ Branch 1 not taken.
282589 mi->finished_queueing();
7252
7253
1/2
✓ Branch 0 taken 282589 times.
✗ Branch 1 not taken.
282589 Trx_monitoring_info processing;
7254
1/2
✓ Branch 0 taken 282589 times.
✗ Branch 1 not taken.
282589 Trx_monitoring_info last;
7255
1/2
✓ Branch 0 taken 282589 times.
✗ Branch 1 not taken.
282589 mi->get_gtid_monitoring_info()->copy_info_to(&processing, &last);
7256
7257 // update the compression information
7258
1/2
✓ Branch 0 taken 282589 times.
✗ Branch 1 not taken.
282589 binlog::global_context.monitoring_context()
7259
1/2
✓ Branch 0 taken 282589 times.
✗ Branch 1 not taken.
282589 .transaction_compression()
7260 282589 .update(binlog::monitoring::log_type::RELAY, last.compression_type,
7261 282589 last.gtid, last.end_time, last.compressed_bytes,
7262
1/2
✓ Branch 0 taken 282589 times.
✗ Branch 1 not taken.
282589 last.uncompressed_bytes,
7263 282589 mi->rli->get_gtid_set()->get_sid_map());
7264 }
7265
1/2
✓ Branch 0 taken 325129 times.
✗ Branch 1 not taken.
325129 mysql_mutex_unlock(&mi->data_lock);
7266
7267 /*
7268 If relay log is too big, rotate. But only if not in the middle of a
7269 transaction when GTIDs are enabled.
7270
7271 Also rotate if a deferred flush request has been placed.
7272
7273 We now try to mimic the following master binlog behavior: "A transaction
7274 is written in one chunk to the binary log, so it is never split between
7275 several binary logs. Therefore, if you have big transactions, you might
7276 see binary log files larger than max_binlog_size."
7277 */
7278 325129 if (m_binlog_file->get_real_file_size() >
7279
6/8
✓ Branch 0 taken 325129 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325129 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 324942 times.
✓ Branch 5 taken 187 times.
✓ Branch 6 taken 188 times.
✓ Branch 7 taken 324941 times.
650071 DBUG_EVALUATE_IF("rotate_replica_debug_group", 500, max_size) ||
7280
3/4
✓ Branch 0 taken 324942 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 324941 times.
324942 mi->is_rotate_requested()) {
7281
1/2
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
188 error = new_file_without_locking(mi->get_mi_description_event());
7282
1/2
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
188 mi->clear_rotate_requests();
7283 }
7284 }
7285 }
7286
7287
1/2
✓ Branch 0 taken 1556617 times.
✗ Branch 1 not taken.
1556617 lock_binlog_end_pos();
7288 1556617 mi->rli->ign_master_log_name_end[0] = 0;
7289
1/2
✓ Branch 0 taken 1556617 times.
✗ Branch 1 not taken.
1556617 update_binlog_end_pos(false /*need_lock*/);
7290
1/2
✓ Branch 0 taken 1556617 times.
✗ Branch 1 not taken.
1556617 harvest_bytes_written(mi->rli, true /*need_log_space_lock=true*/);
7291
1/2
✓ Branch 0 taken 1556617 times.
✗ Branch 1 not taken.
1556617 unlock_binlog_end_pos();
7292
7293 1556617 return error;
7294 1556617 }
7295
7296 11666 bool MYSQL_BIN_LOG::write_event(Log_event *ev, Master_info *mi) {
7297
1/2
✓ Branch 0 taken 11666 times.
✗ Branch 1 not taken.
11666 DBUG_TRACE;
7298
7299
3/4
✓ Branch 0 taken 11666 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 11665 times.
11666 DBUG_EXECUTE_IF("fail_to_write_ignored_event_to_relay_log", { return true; });
7300 // check preconditions
7301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11665 times.
11665 assert(is_relay_log);
7302
7303 mysql_mutex_assert_owner(&LOCK_log);
7304
7305 // write data
7306 11665 bool error = false;
7307
2/4
✓ Branch 0 taken 11665 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11665 times.
✗ Branch 3 not taken.
11665 if (!binary_event_serialize(ev, m_binlog_file)) {
7308 11665 bytes_written += ev->common_header->data_written;
7309
1/2
✓ Branch 0 taken 11665 times.
✗ Branch 1 not taken.
11665 error = after_write_to_relay_log(mi);
7310 } else {
7311 mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
7312 ER_THD(current_thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
7313 "failed to write event to the relay log file");
7314 truncate_relaylog_file(mi, atomic_binlog_end_pos);
7315 error = true;
7316 }
7317
7318 11665 return error;
7319 11666 }
7320
7321 1544952 bool MYSQL_BIN_LOG::write_buffer(uchar *buf, uint len, Master_info *mi) {
7322
1/2
✓ Branch 0 taken 1544952 times.
✗ Branch 1 not taken.
1544952 DBUG_TRACE;
7323
7324 // check preconditions
7325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1544952 times.
1544952 assert(is_relay_log);
7326 mysql_mutex_assert_owner(&LOCK_log);
7327
7328 // write data
7329 1544952 bool error = false;
7330
2/4
✓ Branch 0 taken 1544952 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1544952 times.
✗ Branch 3 not taken.
1544952 if (m_binlog_file->write(pointer_cast<const uchar *>(buf), len) == 0) {
7331 1544952 bytes_written += len;
7332
1/2
✓ Branch 0 taken 1544952 times.
✗ Branch 1 not taken.
1544952 error = after_write_to_relay_log(mi);
7333 } else {
7334 mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
7335 ER_THD(current_thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
7336 "failed to write event to the relay log file");
7337 truncate_relaylog_file(mi, atomic_binlog_end_pos);
7338 error = true;
7339 }
7340
7341 1544952 return error;
7342 1544952 }
7343
7344 12477 bool MYSQL_BIN_LOG::flush() {
7345
3/4
✓ Branch 0 taken 12474 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12474 times.
12477 return m_binlog_file->is_open() && m_binlog_file->flush();
7346 }
7347
7348 1564690 bool MYSQL_BIN_LOG::flush_and_sync(const bool force) {
7349 mysql_mutex_assert_owner(&LOCK_log);
7350
7351
3/4
✓ Branch 0 taken 1564690 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1564684 times.
1564690 if (m_binlog_file->flush()) return true;
7352
7353
1/2
✓ Branch 0 taken 1564684 times.
✗ Branch 1 not taken.
1564684 std::pair<bool, bool> result = sync_binlog_file(force);
7354
7355 1564684 return result.first;
7356 }
7357
7358 142457 void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param) {
7359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 142457 times.
142457 assert(!thd->binlog_evt_union.do_union);
7360 142457 thd->binlog_evt_union.do_union = true;
7361 142457 thd->binlog_evt_union.unioned_events = false;
7362 142457 thd->binlog_evt_union.unioned_events_trans = false;
7363 142457 thd->binlog_evt_union.first_query_id = query_id_param;
7364 142457 }
7365
7366 142457 void MYSQL_BIN_LOG::stop_union_events(THD *thd) {
7367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 142457 times.
142457 assert(thd->binlog_evt_union.do_union);
7368 142457 thd->binlog_evt_union.do_union = false;
7369 142457 }
7370
7371 234636 bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param) {
7372
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 234512 times.
234760 return (thd->binlog_evt_union.do_union &&
7373
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 72 times.
234760 query_id_param >= thd->binlog_evt_union.first_query_id);
7374 }
7375
7376 /*
7377 Updates thd's position-of-next-event variables
7378 after a *real* write a file.
7379 */
7380 2590011 void MYSQL_BIN_LOG::update_thd_next_event_pos(THD *thd) {
7381
1/2
✓ Branch 0 taken 2590011 times.
✗ Branch 1 not taken.
2590011 if (likely(thd != nullptr)) {
7382 2590011 thd->set_next_event_pos(log_file_name, m_binlog_file->position());
7383 }
7384 2590011 }
7385
7386 /*
7387 Moves the last bunch of rows from the pending Rows event to a cache (either
7388 transactional cache if is_transaction is @c true, or the non-transactional
7389 cache otherwise. Sets a new pending event.
7390
7391 @param thd a pointer to the user thread.
7392 @param evt a pointer to the row event.
7393 @param is_transactional @c true indicates a transactional cache,
7394 otherwise @c false a non-transactional.
7395 */
7396 8855704 int MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
7397 Rows_log_event *event,
7398 bool is_transactional) {
7399
1/2
✓ Branch 0 taken 8855964 times.
✗ Branch 1 not taken.
8855704 DBUG_TRACE;
7400 #ifdef WITH_WSREP
7401
11/12
✓ Branch 0 taken 8855963 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 317237 times.
✓ Branch 3 taken 8538726 times.
✓ Branch 4 taken 317235 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 317231 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 182 times.
✓ Branch 9 taken 317049 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 8855690 times.
8855964 assert(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open());
7402 #else
7403 assert(mysql_bin_log.is_open());
7404 #endif /* WITH_WSREP */
7405
5/8
✓ Branch 0 taken 8855868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8855900 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 8855857 times.
✓ Branch 6 taken 43 times.
✗ Branch 7 not taken.
8855872 DBUG_PRINT("enter", ("event: %p", event));
7406
7407 8855900 int error = 0;
7408
1/2
✓ Branch 0 taken 8855962 times.
✗ Branch 1 not taken.
8855900 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
7409
7410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8855962 times.
8855962 assert(cache_mngr);
7411
7412 binlog_cache_data *cache_data =
7413 8855962 cache_mngr->get_binlog_cache_data(is_transactional);
7414
7415
5/8
✓ Branch 0 taken 8855890 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8855848 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 8855805 times.
✓ Branch 6 taken 43 times.
✗ Branch 7 not taken.
8855983 DBUG_PRINT("info", ("cache_mngr->pending(): %p", cache_data->pending()));
7416
7417
2/2
✓ Branch 0 taken 4617685 times.
✓ Branch 1 taken 4238184 times.
8855848 if (Rows_log_event *pending = cache_data->pending()) {
7418 /*
7419 Write pending event to the cache.
7420 */
7421
3/4
✓ Branch 0 taken 4617660 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 4617635 times.
4617685 if (cache_data->write_event(pending)) {
7422
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 report_cache_write_error(thd, is_transactional);
7423
5/8
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 20 times.
50 if (check_write_error(thd) && cache_data &&
7424
3/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 20 times.
25 stmt_cannot_safely_rollback(thd))
7425 5 cache_data->set_incident();
7426
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 delete pending;
7427 25 cache_data->set_pending(nullptr);
7428 25 return 1;
7429 }
7430
7431
1/2
✓ Branch 0 taken 4617638 times.
✗ Branch 1 not taken.
4617635 delete pending;
7432 }
7433
7434 8855861 cache_data->set_pending(event);
7435
7436 8855732 return error;
7437 8855757 }
7438
7439 /**
7440 Write an event to the binary log cache.
7441 */
7442
7443 879451 bool MYSQL_BIN_LOG::write_event(Log_event *event_info) {
7444 879451 THD *thd = event_info->thd;
7445 879451 bool error = true;
7446
1/2
✓ Branch 0 taken 879795 times.
✗ Branch 1 not taken.
879451 DBUG_TRACE;
7447
7448
2/2
✓ Branch 0 taken 15414 times.
✓ Branch 1 taken 864381 times.
879795 if (thd->binlog_evt_union.do_union) {
7449 /*
7450 In Stored function; Remember that function call caused an update.
7451 We will log the function call to the binary log on function exit
7452 */
7453 15414 thd->binlog_evt_union.unioned_events = true;
7454 15414 thd->binlog_evt_union.unioned_events_trans |=
7455 15414 event_info->is_using_trans_cache();
7456 15414 return false;
7457 }
7458
7459 /*
7460 We only end the statement if we are in a top-level statement. If
7461 we are inside a stored function, we do not end the statement since
7462 this will close all tables on the slave. But there can be a special case
7463 where we are inside a stored function/trigger and a SAVEPOINT is being
7464 set in side the stored function/trigger. This SAVEPOINT execution will
7465 force the pending event to be flushed without an STMT_END_F flag. This
7466 will result in a case where following DMLs will be considered as part of
7467 same statement and result in data loss on slave. Hence in this case we
7468 force the end_stmt to be true.
7469 */
7470 bool const end_stmt =
7471
2/2
✓ Branch 0 taken 1922 times.
✓ Branch 1 taken 32 times.
1954 (thd->in_sub_stmt && thd->lex->sql_command == SQLCOM_SAVEPOINT)
7472
2/2
✓ Branch 0 taken 1954 times.
✓ Branch 1 taken 862427 times.
1728762 ? true
7473
4/4
✓ Branch 0 taken 15209 times.
✓ Branch 1 taken 849140 times.
✓ Branch 2 taken 12715 times.
✓ Branch 3 taken 2494 times.
864349 : (thd->locked_tables_mode && thd->lex->requires_prelocking());
7474
2/4
✓ Branch 0 taken 864402 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 864402 times.
864160 if (thd->binlog_flush_pending_rows_event(end_stmt,
7475 864381 event_info->is_using_trans_cache()))
7476 return error;
7477
7478 /*
7479 In most cases this is only called if 'is_open()' is true; in fact this is
7480 mostly called if is_open() *was* true a few instructions before, but it
7481 could have changed since.
7482 */
7483 #ifdef WITH_WSREP
7484 /* If applier thread can have log-slave-updates=1 there-by causing
7485 applier action to get binlogged.
7486 But this should be avoided if applier thread is operating in emulation
7487 binlog mode. */
7488
13/18
✓ Branch 0 taken 864407 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16658 times.
✓ Branch 3 taken 847749 times.
✓ Branch 4 taken 16643 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 12244 times.
✓ Branch 7 taken 4399 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 12242 times.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 8 times.
✓ Branch 14 taken 864233 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 864301 times.
✗ Branch 17 not taken.
864402 if ((WSREP_EMULATE_BINLOG(thd) && !wsrep_thd_is_applying(thd)) || is_open()) {
7489 #else
7490 if (likely(is_open())) {
7491 #endif /* WITH_WSREP */
7492 /*
7493 In the future we need to add to the following if tests like
7494 "do the involved tables match (to be implemented)
7495 binlog_[wild_]{do|ignore}_table?" (WL#1049)"
7496 */
7497
1/2
✓ Branch 0 taken 864216 times.
✗ Branch 1 not taken.
864301 const char *local_db = event_info->get_db();
7498
5/6
✓ Branch 0 taken 864355 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 747419 times.
✓ Branch 3 taken 116936 times.
✓ Branch 4 taken 117186 times.
✓ Branch 5 taken 747177 times.
1611643 if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) ||
7499
1/2
✓ Branch 0 taken 747439 times.
✗ Branch 1 not taken.
747280 (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT &&
7500
2/2
✓ Branch 0 taken 739565 times.
✓ Branch 1 taken 7874 times.
747439 thd->lex->sql_command != SQLCOM_SAVEPOINT &&
7501
2/2
✓ Branch 0 taken 739271 times.
✓ Branch 1 taken 199 times.
739565 (!event_info->is_no_filter_event() &&
7502
3/4
✓ Branch 0 taken 739513 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 250 times.
✓ Branch 3 taken 739263 times.
739271 !binlog_filter->db_ok(local_db))))
7503 117186 return false;
7504
7505
3/4
✓ Branch 0 taken 163526 times.
✓ Branch 1 taken 583653 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 163547 times.
747177 assert(event_info->is_using_trans_cache() ||
7506 event_info->is_using_stmt_cache());
7507
7508
2/4
✓ Branch 0 taken 747207 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 747207 times.
747200 if (binlog_start_trans_and_stmt(thd, event_info)) return error;
7509
7510 747207 bool is_trans_cache = event_info->is_using_trans_cache();
7511
1/2
✓ Branch 0 taken 747229 times.
✗ Branch 1 not taken.
747211 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
7512 binlog_cache_data *cache_data =
7513 747229 cache_mngr->get_binlog_cache_data(is_trans_cache);
7514
7515
5/8
✓ Branch 0 taken 747133 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 747107 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 95 times.
✓ Branch 5 taken 747012 times.
✓ Branch 6 taken 61 times.
✗ Branch 7 not taken.
747231 DBUG_PRINT("info", ("event type: %d", event_info->get_type_code()));
7516
7517 /*
7518 No check for auto events flag here - this write method should
7519 never be called if auto-events are enabled.
7520
7521 Write first log events which describe the 'run environment'
7522 of the SQL command. If row-based binlogging, Insert_id, Rand
7523 and other kind of "setting context" events are not needed.
7524 */
7525
1/2
✓ Branch 0 taken 747073 times.
✗ Branch 1 not taken.
747073 if (thd) {
7526
2/2
✓ Branch 0 taken 415241 times.
✓ Branch 1 taken 331843 times.
747073 if (!thd->is_current_stmt_binlog_format_row()) {
7527
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 415058 times.
415241 if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt) {
7528 Intvar_log_event e(
7529 thd, (uchar)binary_log::Intvar_event::LAST_INSERT_ID_EVENT,
7530 thd->first_successful_insert_id_in_prev_stmt_for_binlog,
7531
1/2
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
183 event_info->event_cache_type, event_info->event_logging_type);
7532
2/4
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 183 times.
183 if (cache_data->write_event(&e)) goto err;
7533
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 182 times.
183 if (event_info->is_using_immediate_logging())
7534 1 thd->binlog_bytes_written += e.header()->data_written;
7535
1/2
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
183 }
7536
2/2
✓ Branch 0 taken 87250 times.
✓ Branch 1 taken 327825 times.
415241 if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0) {
7537
3/8
✓ Branch 0 taken 87250 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87250 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 87250 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
87250 DBUG_PRINT(
7538 "info",
7539 ("number of auto_inc intervals: %u",
7540 thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements()));
7541 Intvar_log_event e(
7542 thd, (uchar)binary_log::Intvar_event::INSERT_ID_EVENT,
7543 thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum(),
7544
1/2
✓ Branch 0 taken 87250 times.
✗ Branch 1 not taken.
87250 event_info->event_cache_type, event_info->event_logging_type);
7545
2/4
✓ Branch 0 taken 87250 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 87250 times.
87250 if (cache_data->write_event(&e)) goto err;
7546
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 87179 times.
87250 if (event_info->is_using_immediate_logging())
7547 71 thd->binlog_bytes_written += e.header()->data_written;
7548
1/2
✓ Branch 0 taken 87250 times.
✗ Branch 1 not taken.
87250 }
7549
2/2
✓ Branch 0 taken 2098 times.
✓ Branch 1 taken 412977 times.
415075 if (thd->rand_used) {
7550 2098 Rand_log_event e(thd, thd->rand_saved_seed1, thd->rand_saved_seed2,
7551 event_info->event_cache_type,
7552
1/2
✓ Branch 0 taken 2098 times.
✗ Branch 1 not taken.
2098 event_info->event_logging_type);
7553
2/4
✓ Branch 0 taken 2098 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2098 times.
2098 if (cache_data->write_event(&e)) goto err;
7554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2098 times.
2098 if (event_info->is_using_immediate_logging())
7555 thd->binlog_bytes_written += e.header()->data_written;
7556
1/2
✓ Branch 0 taken 2098 times.
✗ Branch 1 not taken.
2098 }
7557
3/4
✓ Branch 0 taken 415091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9034 times.
✓ Branch 3 taken 406057 times.
415075 if (!thd->user_var_events.empty()) {
7558
3/4
✓ Branch 0 taken 18143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9109 times.
✓ Branch 3 taken 9034 times.
18143 for (size_t i = 0; i < thd->user_var_events.size(); i++) {
7559
1/2
✓ Branch 0 taken 9109 times.
✗ Branch 1 not taken.
9109 Binlog_user_var_event *user_var_event = thd->user_var_events[i];
7560
7561 /* setting flags for user var log event */
7562 9109 uchar flags = User_var_log_event::UNDEF_F;
7563
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 9098 times.
9109 if (user_var_event->unsigned_flag)
7564 11 flags |= User_var_log_event::UNSIGNED_F;
7565
7566 User_var_log_event e(
7567 9109 thd, user_var_event->user_var_event->entry_name.ptr(),
7568 9109 user_var_event->user_var_event->entry_name.length(),
7569 user_var_event->value, user_var_event->length,
7570 user_var_event->type, user_var_event->charset_number, flags,
7571
1/2
✓ Branch 0 taken 9109 times.
✗ Branch 1 not taken.
9109 event_info->event_cache_type, event_info->event_logging_type);
7572
2/4
✓ Branch 0 taken 9109 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9109 times.
9109 if (cache_data->write_event(&e)) goto err;
7573
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 9081 times.
9109 if (event_info->is_using_immediate_logging())
7574 28 thd->binlog_bytes_written += e.header()->data_written;
7575
1/2
✓ Branch 0 taken 9109 times.
✗ Branch 1 not taken.
9109 }
7576 }
7577 }
7578 }
7579
7580 /*
7581 Write the event.
7582 */
7583
3/4
✓ Branch 0 taken 747209 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 747156 times.
746934 if (cache_data->write_event(event_info)) goto err;
7584
7585
3/4
✓ Branch 0 taken 747158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 747121 times.
747156 if (DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0)) goto err;
7586
2/2
✓ Branch 0 taken 91295 times.
✓ Branch 1 taken 655821 times.
747121 if (event_info->is_using_immediate_logging())
7587 91295 thd->binlog_bytes_written += event_info->common_header->data_written;
7588
7589 /*
7590 After writing the event, if the trx-cache was used and any unsafe
7591 change was written into it, the cache is marked as cannot safely
7592 roll back.
7593 */
7594
7/8
✓ Branch 0 taken 583587 times.
✓ Branch 1 taken 163529 times.
✓ Branch 2 taken 583580 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1184 times.
✓ Branch 5 taken 582396 times.
✓ Branch 6 taken 1184 times.
✓ Branch 7 taken 745925 times.
747116 if (is_trans_cache && stmt_cannot_safely_rollback(thd))
7595 1184 cache_mngr->trx_cache.set_cannot_rollback();
7596
7597 747049 error = false;
7598
7599 747139 err:
7600
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 747049 times.
747139 if (error) {
7601
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 report_cache_write_error(thd, is_trans_cache);
7602
5/8
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 86 times.
180 if (check_write_error(thd) && cache_data &&
7603
3/4
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 86 times.
90 stmt_cannot_safely_rollback(thd))
7604 4 cache_data->set_incident();
7605 }
7606 }
7607
7608 747082 return error;
7609 879682 }
7610
7611 /**
7612 The method executes rotation when LOCK_log is already acquired
7613 by the caller.
7614
7615 @param force_rotate caller can request the log rotation
7616 @param check_purge is set to true if rotation took place
7617
7618 @note
7619 If rotation fails, for instance the server was unable
7620 to create a new log file, we still try to write an
7621 incident event to the current log.
7622
7623 @note The caller must hold LOCK_log when invoking this function.
7624
7625 @retval
7626 nonzero - error in rotating routine.
7627 */
7628 12737 int MYSQL_BIN_LOG::rotate(bool force_rotate, bool *check_purge) {
7629 12737 int error = 0;
7630
1/2
✓ Branch 0 taken 12737 times.
✗ Branch 1 not taken.
12737 DBUG_TRACE;
7631 #ifdef WITH_WSREP
7632
5/6
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 12497 times.
✓ Branch 2 taken 240 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 238 times.
12737 if (WSREP_ON && wsrep_to_isolation) {
7633 2 *check_purge = false;
7634
1/24
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
2 WSREP_DEBUG("avoiding binlog rotate due to TO isolation: %d",
7635 wsrep_to_isolation);
7636 2 return 0;
7637 }
7638 #endif /* WITH_WSREP */
7639
7640
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12735 times.
12735 assert(!is_relay_log);
7641 mysql_mutex_assert_owner(&LOCK_log);
7642
7643 12735 *check_purge = false;
7644
7645
3/4
✓ Branch 0 taken 12735 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9698 times.
✓ Branch 3 taken 3037 times.
25470 if (DBUG_EVALUATE_IF("force_rotate", 1, 0) || force_rotate ||
7646
5/6
✓ Branch 0 taken 12735 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4730 times.
✓ Branch 3 taken 4968 times.
✓ Branch 4 taken 8006 times.
✓ Branch 5 taken 4729 times.
30200 (m_binlog_file->get_real_file_size() >= (my_off_t)max_size) ||
7647
3/4
✓ Branch 0 taken 4730 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4729 times.
4730 DBUG_EVALUATE_IF("simulate_max_binlog_size", true, false)) {
7648
1/2
✓ Branch 0 taken 8006 times.
✗ Branch 1 not taken.
8006 error = new_file_without_locking(nullptr);
7649 8006 *check_purge = true;
7650
1/2
✓ Branch 0 taken 8006 times.
✗ Branch 1 not taken.
8006 publish_coordinates_for_global_status();
7651 }
7652 12735 return error;
7653 12737 }
7654
7655 8986 void MYSQL_BIN_LOG::auto_purge_at_server_startup() {
7656 // first run the auto purge validations
7657
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8980 times.
8986 if (check_auto_purge_conditions()) return;
7658
7659 8980 auto purge_time = calculate_auto_purge_lower_time_bound();
7660 8980 constexpr auto auto_purge{true};
7661 8980 purge_logs_before_date(purge_time, auto_purge);
7662 }
7663
7664 /**
7665 The method executes logs purging routine.
7666 */
7667 6995 void MYSQL_BIN_LOG::auto_purge() {
7668 // first run the auto purge validations
7669
3/4
✓ Branch 0 taken 6995 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 6972 times.
7025 if (check_auto_purge_conditions()) return;
7670
7671 // then we run the purge validations
7672 // if we run into out of memory, execute binlog_error_action_abort
7673
1/2
✓ Branch 0 taken 6972 times.
✗ Branch 1 not taken.
6972 const auto [is_invalid_purge, purge_error] = check_purge_conditions(*this);
7674
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6942 times.
6972 if (is_invalid_purge) {
7675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (purge_error == LOG_INFO_MEM) {
7676 /* purecov: begin inspected */
7677 // OOM
7678 exec_binlog_error_action_abort(
7679 "Out of memory happened while checking if "
7680 "instance was locked for backup");
7681 /* purecov: end */
7682 }
7683 30 return;
7684 }
7685
7686
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6942 times.
6942 assert(purge_error == 0);
7687
7688
3/6
✓ Branch 0 taken 6942 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6942 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6942 times.
✗ Branch 5 not taken.
6942 DEBUG_SYNC(current_thd, "at_purge_logs_before_date");
7689
7690
1/2
✓ Branch 0 taken 6942 times.
✗ Branch 1 not taken.
6942 auto purge_time = calculate_auto_purge_lower_time_bound();
7691 6942 constexpr auto auto_purge{true};
7692 /*
7693 Flush logs for storage engines, so that the last transaction
7694 is persisted inside storage engines.
7695 */
7696
1/2
✓ Branch 0 taken 6942 times.
✗ Branch 1 not taken.
6942 ha_flush_logs();
7697
1/2
✓ Branch 0 taken 6942 times.
✗ Branch 1 not taken.
6942 purge_logs_before_date(purge_time, auto_purge);
7698
7699
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 6900 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
6942 if (binlog_space_limit) purge_logs_by_size(true);
7700 }
7701
7702 /**
7703 Execute a FLUSH LOGS statement.
7704
7705 The method is a shortcut of @c rotate() and @c purge().
7706 LOCK_log is acquired prior to rotate and is released after it.
7707
7708 @param thd Current session.
7709 @param force_rotate caller can request the log rotation
7710
7711 @retval
7712 nonzero - error in rotating routine.
7713 */
7714 1997 int MYSQL_BIN_LOG::rotate_and_purge(THD *thd, bool force_rotate) {
7715 1997 int error = 0;
7716
1/2
✓ Branch 0 taken 1997 times.
✗ Branch 1 not taken.
1997 DBUG_TRACE;
7717 1997 bool check_purge = false;
7718
7719 /*
7720 FLUSH BINARY LOGS command should ignore 'read-only' and 'super_read_only'
7721 options so that it can update 'mysql.gtid_executed' replication repository
7722 table.
7723 */
7724 1997 thd->set_skip_readonly_check();
7725 /*
7726 Wait for handlerton to insert any pending information into the binlog.
7727 For e.g. ha_ndbcluster which updates the binlog asynchronously this is
7728 needed so that the user see its own commands in the binlog.
7729 */
7730
1/2
✓ Branch 0 taken 1997 times.
✗ Branch 1 not taken.
1997 ha_binlog_wait(thd);
7731
7732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1997 times.
1997 assert(!is_relay_log);
7733
1/2
✓ Branch 0 taken 1997 times.
✗ Branch 1 not taken.
1997 mysql_mutex_lock(&LOCK_log);
7734
1/2
✓ Branch 0 taken 1997 times.
✗ Branch 1 not taken.
1997 error = rotate(force_rotate, &check_purge);
7735 /*
7736 NOTE: Run purge_logs wo/ holding LOCK_log because it does not need
7737 the mutex. Otherwise causes various deadlocks.
7738 */
7739
1/2
✓ Branch 0 taken 1997 times.
✗ Branch 1 not taken.
1997 mysql_mutex_unlock(&LOCK_log);
7740
7741
5/6
✓ Branch 0 taken 1981 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1979 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1979 times.
✗ Branch 5 not taken.
1997 if (!error && check_purge) auto_purge();
7742
7743 1997 return error;
7744 1997 }
7745
7746 4027 uint MYSQL_BIN_LOG::next_file_id() {
7747 uint res;
7748 4027 mysql_mutex_lock(&LOCK_log);
7749 4027 res = file_id++;
7750 4027 mysql_mutex_unlock(&LOCK_log);
7751 4027 return res;
7752 }
7753
7754 13259 int MYSQL_BIN_LOG::get_gtid_executed(Sid_map *sid_map, Gtid_set *gtid_set) {
7755
1/2
✓ Branch 0 taken 13259 times.
✗ Branch 1 not taken.
13259 DBUG_TRACE;
7756 13259 int error = 0;
7757
7758
1/2
✓ Branch 0 taken 13259 times.
✗ Branch 1 not taken.
13259 mysql_mutex_lock(&mysql_bin_log.LOCK_commit);
7759
1/2
✓ Branch 0 taken 13259 times.
✗ Branch 1 not taken.
13259 global_sid_lock->wrlock();
7760
7761
1/2
✓ Branch 0 taken 13259 times.
✗ Branch 1 not taken.
13259 enum_return_status return_status = global_sid_map->copy(sid_map);
7762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13259 times.
13259 if (return_status != RETURN_STATUS_OK) {
7763 error = 1;
7764 goto end;
7765 }
7766
7767
1/2
✓ Branch 0 taken 13259 times.
✗ Branch 1 not taken.
13259 return_status = gtid_set->add_gtid_set(gtid_state->get_executed_gtids());
7768
1/2
✓ Branch 0 taken 13259 times.
✗ Branch 1 not taken.
13259 if (return_status != RETURN_STATUS_OK) error = 1;
7769
7770 13259 end:
7771
1/2
✓ Branch 0 taken 13259 times.
✗ Branch 1 not taken.
13259 global_sid_lock->unlock();
7772
1/2
✓ Branch 0 taken 13259 times.
✗ Branch 1 not taken.
13259 mysql_mutex_unlock(&mysql_bin_log.LOCK_commit);
7773
7774 13259 return error;
7775 13259 }
7776
7777 /**
7778 Write the contents of the given IO_CACHE to the binary log.
7779
7780 The cache will be reset as a READ_CACHE to be able to read the
7781 contents from it.
7782
7783 The data will be post-processed: see class Binlog_event_writer for
7784 details.
7785
7786 @param cache Events will be read from this IO_CACHE.
7787 @param writer Events will be written to this Binlog_event_writer.
7788
7789 @retval true IO error.
7790 @retval false Success.
7791
7792 @see MYSQL_BIN_LOG::write_cache
7793 */
7794 2590017 bool MYSQL_BIN_LOG::do_write_cache(Binlog_cache_storage *cache,
7795 Binlog_event_writer *writer) {
7796
1/2
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
2590017 DBUG_TRACE;
7797
7798
4/6
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2590016 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2590017 DBUG_EXECUTE_IF("simulate_do_write_cache_failure", {
7799 /*
7800 see binlog_cache_data::write_event() that reacts on
7801 @c simulate_disk_full_at_flush_pending.
7802 */
7803 DBUG_SET("-d,simulate_do_write_cache_failure");
7804 return true;
7805 });
7806
7807 #ifndef NDEBUG
7808
1/2
✓ Branch 0 taken 2590016 times.
✗ Branch 1 not taken.
2590016 uint64 expected_total_len = cache->length();
7809
5/8
✓ Branch 0 taken 2590016 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590016 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 114 times.
✓ Branch 5 taken 2589902 times.
✓ Branch 6 taken 114 times.
✗ Branch 7 not taken.
2590016 DBUG_PRINT("info", ("bytes in cache= %" PRIu64, expected_total_len));
7810 #endif
7811
7812 2590016 bool error = false;
7813
3/4
✓ Branch 0 taken 2590016 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2590014 times.
2590016 if (cache->copy_to(writer, &error)) {
7814
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (error) report_binlog_write_error();
7815 2 return true;
7816 }
7817 2590014 return false;
7818 2590017 }
7819
7820 /**
7821 Writes an incident event to stmt_cache.
7822
7823 @param ev Incident event to be written
7824 @param thd Thread variable
7825 @param need_lock_log If true, will acquire LOCK_log; otherwise the
7826 caller should already have acquired LOCK_log.
7827 @param err_msg Error message written to log file for the incident.
7828 @param do_flush_and_sync If true, will call flush_and_sync(), rotate() and
7829 purge().
7830
7831 @retval false error
7832 @retval true success
7833 */
7834 11 bool MYSQL_BIN_LOG::write_incident(Incident_log_event *ev, THD *thd,
7835 bool need_lock_log, const char *err_msg,
7836 bool do_flush_and_sync) {
7837 11 uint error = 0;
7838
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 DBUG_TRACE;
7839
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 assert(err_msg);
7840
7841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!is_open()) return error;
7842
7843
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
7844
7845 /*
7846 thd->cache_mngr may be uninitialized when first transaction resulted in an
7847 incident. If there is no cache manager exists for the session, then we
7848 create one, so that a GTID is generated and is written prior to flushing
7849 the stmt_cache.
7850 */
7851
3/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
22 if (cache_mngr == nullptr ||
7852
3/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
11 DBUG_EVALUATE_IF("simulate_cache_creation_failure", 1, 0)) {
7853
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 if (thd->binlog_setup_trx_data() ||
7854
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 DBUG_EVALUATE_IF("simulate_cache_creation_failure", 1, 0)) {
7855
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 auto gtid_mode = global_gtid_mode.get();
7856
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (gtid_mode == Gtid_mode::ON || gtid_mode == Gtid_mode::ON_PERMISSIVE) {
7857
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::ostringstream message;
7858
7859 message << "Could not create IO cache while writing an incident event "
7860
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 "to the binary log. Since GTID_MODE = "
7861
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 << gtid_mode
7862
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 << ", server is unable to proceed with logging. Query: '";
7863 /**
7864 The reason for the error may be that the query was
7865 huge. Better cut it to not run into resource problems.
7866 */
7867
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 message.write(thd->query().str, MYSQL_ERRMSG_SIZE);
7868
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 message << "'.";
7869
7870
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 handle_binlog_flush_or_sync_error(thd, true, message.str().c_str());
7871 1 return true;
7872 1 }
7873 } else
7874 cache_mngr = thd_get_cache_mngr(thd);
7875 }
7876
7877 #ifndef NDEBUG
7878
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (DBUG_EVALUATE_IF("simulate_write_incident_event_into_binlog_directly", 1,
7879
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
11 0) &&
7880
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 !cache_mngr->stmt_cache.is_binlog_empty()) {
7881 /* The stmt_cache contains corruption data, so we can reset it. */
7882
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 cache_mngr->stmt_cache.reset();
7883 }
7884 #endif
7885
7886 /*
7887 If there is no binlog cache then we write incidents directly
7888 into the binlog. If caller needs GTIDs it has to setup the
7889 binlog cache (for the injector thread).
7890 */
7891
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
20 if (cache_mngr == nullptr ||
7892
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
10 DBUG_EVALUATE_IF("simulate_write_incident_event_into_binlog_directly", 1,
7893 0)) {
7894
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (need_lock_log)
7895
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 mysql_mutex_lock(&LOCK_log);
7896 else
7897 mysql_mutex_assert_owner(&LOCK_log);
7898 /* Write an incident event into binlog directly. */
7899
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 error = write_event_to_binlog(ev);
7900 /*
7901 Write an error to log. So that user might have a chance
7902 to be alerted and explore incident details.
7903 */
7904
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!error)
7905
8/16
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 LogErr(ERROR_LEVEL, ER_BINLOG_LOGGING_INCIDENT_TO_STOP_SLAVES, err_msg);
7906 } else // (cache_mngr != NULL)
7907 {
7908
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
9 if (!cache_mngr->stmt_cache.is_binlog_empty()) {
7909 /* The stmt_cache contains corruption data, so we can reset it. */
7910
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 cache_mngr->stmt_cache.reset();
7911 }
7912
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
9 if (!cache_mngr->trx_cache.is_binlog_empty()) {
7913 /* The trx_cache contains corruption data, so we can reset it. */
7914
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 cache_mngr->trx_cache.reset();
7915 }
7916 /*
7917 Write the incident event into stmt_cache, so that a GTID is generated and
7918 written for it prior to flushing the stmt_cache.
7919 */
7920 9 binlog_cache_data *cache_data = cache_mngr->get_binlog_cache_data(false);
7921
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
9 if ((error = cache_data->write_event(ev))) {
7922 LogErr(ERROR_LEVEL, ER_BINLOG_EVENT_WRITE_TO_STMT_CACHE_FAILED);
7923 cache_mngr->stmt_cache.reset();
7924 return error;
7925 }
7926
7927
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (need_lock_log)
7928
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql_mutex_lock(&LOCK_log);
7929 else
7930 mysql_mutex_assert_owner(&LOCK_log);
7931 }
7932
7933
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if (do_flush_and_sync) {
7934
4/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 if (!error && !(error = flush_and_sync())) {
7935 8 bool check_purge = false;
7936
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 update_binlog_end_pos();
7937 8 is_rotating_caused_by_incident = true;
7938
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 error = rotate(true, &check_purge);
7939 8 is_rotating_caused_by_incident = false;
7940
3/6
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 if (!error && check_purge) auto_purge();
7941 }
7942 }
7943
7944
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
10 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
7945
7946 /*
7947 Write an error to log. So that user might have a chance
7948 to be alerted and explore incident details.
7949 */
7950
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 if (!error && cache_mngr != nullptr)
7951
8/16
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 10 times.
✗ Branch 15 not taken.
10 LogErr(ERROR_LEVEL, ER_BINLOG_LOGGING_INCIDENT_TO_STOP_SLAVES, err_msg);
7952
7953 10 return error;
7954 11 }
7955
7956 56 bool MYSQL_BIN_LOG::write_stmt_directly(THD *thd, const char *stmt,
7957 size_t stmt_len,
7958 enum_sql_command sql_command) {
7959 56 bool ret = false;
7960 /* backup the original command */
7961 56 enum_sql_command save_sql_command = thd->lex->sql_command;
7962 56 thd->lex->sql_command = sql_command;
7963
7964 56 if (thd->binlog_query(THD::STMT_QUERY_TYPE, stmt, stmt_len, false, false,
7965
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
112 false, 0) ||
7966
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 commit(thd, false) != TC_LOG::RESULT_SUCCESS) {
7967 ret = true;
7968 }
7969
7970 56 thd->lex->sql_command = save_sql_command;
7971 56 return ret;
7972 }
7973
7974 /**
7975 Creates an incident event and writes it to the binary log.
7976
7977 @param thd Thread variable
7978 @param need_lock_log If the binary lock should be locked or not
7979 @param err_msg Error message written to log file for the incident.
7980 @param do_flush_and_sync If true, will call flush_and_sync(), rotate() and
7981 purge().
7982
7983 @retval
7984 0 error
7985 @retval
7986 1 success
7987 */
7988 11 bool MYSQL_BIN_LOG::write_incident(THD *thd, bool need_lock_log,
7989 const char *err_msg,
7990 bool do_flush_and_sync) {
7991
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 DBUG_TRACE;
7992
7993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!is_open()) return false;
7994
7995 11 LEX_CSTRING write_error_msg = {err_msg, strlen(err_msg)};
7996 11 binary_log::Incident_event::enum_incident incident =
7997 binary_log::Incident_event::INCIDENT_LOST_EVENTS;
7998
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 Incident_log_event ev(thd, incident, write_error_msg);
7999
8000
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 return write_incident(&ev, thd, need_lock_log, err_msg, do_flush_and_sync);
8001 11 }
8002
8003 /*
8004 Write the event into current binlog directly without going though a session
8005 binlog cache. It will update the event's log_pos and set checksum accordingly.
8006 binary_event_serialize can be called directly if log_pos should not be
8007 updated.
8008 */
8009 205802 inline bool MYSQL_BIN_LOG::write_event_to_binlog(Log_event *ev) {
8010 205802 ev->common_footer->checksum_alg =
8011 205802 is_relay_log
8012
2/2
✓ Branch 0 taken 137926 times.
✓ Branch 1 taken 67876 times.
205802 ? relay_log_checksum_alg
8013 67876 : static_cast<enum_binlog_checksum_alg>(binlog_checksum_options);
8014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205802 times.
205802 assert(ev->common_footer->checksum_alg !=
8015 binary_log::BINLOG_CHECKSUM_ALG_UNDEF);
8016
8017 /*
8018 Stores current position into log_pos, it is used to calculate correctly
8019 end_log_pos by adding data_written in Log_event::write_header().
8020 */
8021 205802 ev->common_header->log_pos = m_binlog_file->position();
8022
8023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205802 times.
205801 if (binary_event_serialize(ev, m_binlog_file)) return true;
8024
8025 205802 add_bytes_written(ev->common_header->data_written);
8026 205802 return false;
8027 }
8028
8029 /* Write the event into current binlog and flush and sync */
8030 8986 bool MYSQL_BIN_LOG::write_event_to_binlog_and_sync(Log_event *ev) {
8031
3/6
✓ Branch 0 taken 8986 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8986 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8986 times.
17972 if (write_event_to_binlog(ev) || m_binlog_file->flush() ||
8032
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8986 times.
8986 m_binlog_file->sync())
8033 return true;
8034
8035 8986 update_binlog_end_pos();
8036 8986 return false;
8037 }
8038
8039 /**
8040 Write the contents of the statement or transaction cache to the binary log.
8041
8042 Comparison with do_write_cache:
8043
8044 - do_write_cache is a lower-level function that only performs the
8045 actual write.
8046
8047 - write_cache is a higher-level function that calls do_write_cache
8048 and additionally performs some maintenance tasks, including:
8049 - report any errors that occurred
8050 - write incident event if needed
8051 - update gtid_state
8052 - update thd.binlog_next_event_pos
8053
8054 @param thd Thread variable
8055
8056 @param cache_data Events will be read from the IO_CACHE of this
8057 cache_data object.
8058
8059 @param writer Events will be written to this Binlog_event_writer.
8060
8061 @retval true IO error.
8062 @retval false Success.
8063
8064 @note We only come here if there is something in the cache.
8065 @note Whatever is in the cache is always a complete transaction.
8066 @note 'cache' needs to be reinitialized after this functions returns.
8067 */
8068 2590017 bool MYSQL_BIN_LOG::write_cache(THD *thd, binlog_cache_data *cache_data,
8069 Binlog_event_writer *writer) {
8070
1/2
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
2590017 DBUG_TRACE;
8071 #ifdef WITH_WSREP
8072
8/10
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 59129 times.
✓ Branch 3 taken 2530888 times.
✓ Branch 4 taken 59119 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 59063 times.
✓ Branch 7 taken 56 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 59063 times.
2590017 if (WSREP_EMULATE_BINLOG(thd)) return 0;
8073 #endif /* WITH_WSREP */
8074
8075 2590017 Binlog_cache_storage *cache = cache_data->get_cache();
8076 2590017 bool incident = cache_data->has_incident();
8077
8078 mysql_mutex_assert_owner(&LOCK_log);
8079
8080
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2590017 times.
2590017 assert(is_open());
8081
1/2
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
2590017 if (likely(is_open())) // Should always be true
8082 {
8083 /*
8084 We only bother to write to the binary log if there is anything
8085 to write.
8086
8087 @todo Is this check redundant? Probably this is only called if
8088 there is anything in the cache (see @note in comment above this
8089 function). Check if we can replace this by an assertion. /Sven
8090 */
8091
2/4
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2590017 times.
✗ Branch 3 not taken.
2590017 if (!cache->is_empty()) {
8092
2/28
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2590017 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
2590017 DBUG_EXECUTE_IF("crash_before_writing_xid", {
8093 if (do_write_cache(cache, writer))
8094 DBUG_PRINT("info", ("error writing binlog cache: %d", write_error));
8095 flush_and_sync(true);
8096 DBUG_PRINT("info", ("crashing before writing xid"));
8097 DBUG_SUICIDE();
8098 });
8099
3/4
✓ Branch 0 taken 2590017 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2590014 times.
2590017 if (do_write_cache(cache, writer)) goto err;
8100
8101 2590014 const char *err_msg =
8102 "Non-transactional changes did not get into "
8103 "the binlog.";
8104
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2590012 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2590014 times.
2590016 if (incident &&
8105
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 write_incident(thd, false /*need_lock_log=false*/, err_msg,
8106 false /*do_flush_and_sync==false*/)) {
8107 report_binlog_write_error();
8108 goto err;
8109 }
8110
4/6
✓ Branch 0 taken 2590014 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2590011 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
2590014 DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_SUICIDE(););
8111 }
8112
1/2
✓ Branch 0 taken 2590011 times.
✗ Branch 1 not taken.
2590011 update_thd_next_event_pos(thd);
8113 }
8114
8115 2590011 return false;
8116
8117 3 err:
8118 3 thd->commit_error = THD::CE_FLUSH_ERROR;
8119
8120 3 return true;
8121 2590014 }
8122
8123 4 void MYSQL_BIN_LOG::report_binlog_write_error() {
8124 char errbuf[MYSYS_STRERROR_SIZE];
8125
8126 4 write_error = true;
8127
9/18
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 4 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
4 LogErr(ERROR_LEVEL, ER_FAILED_TO_WRITE_TO_FILE, name, errno,
8128 my_strerror(errbuf, sizeof(errbuf), errno));
8129 4 }
8130
8131 /**
8132 Wait until we get a signal that the binary log has been updated.
8133 Applies to master only.
8134
8135 NOTES
8136 @param[in] timeout a pointer to a timespec;
8137 NULL means to wait w/o timeout.
8138 @retval 0 if got signalled on update
8139 @retval non-0 if wait timeout elapsed
8140 @note
8141 LOCK_binlog_end_pos must be taken before calling this function.
8142 LOCK_binlog_end_pos is being released while the thread is waiting.
8143 LOCK_binlog_end_pos is released by the caller.
8144 */
8145
8146 548799 int MYSQL_BIN_LOG::wait_for_update(const struct timespec *timeout) {
8147 548799 int ret = 0;
8148
1/2
✓ Branch 0 taken 548799 times.
✗ Branch 1 not taken.
548799 DBUG_TRACE;
8149
8150
2/2
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 548646 times.
548799 if (!timeout)
8151
1/2
✓ Branch 0 taken 153 times.
✗ Branch 1 not taken.
153 mysql_cond_wait(&update_cond, &LOCK_binlog_end_pos);
8152 else
8153
1/2
✓ Branch 0 taken 548495 times.
✗ Branch 1 not taken.
548646 ret = mysql_cond_timedwait(&update_cond, &LOCK_binlog_end_pos,
8154 const_cast<struct timespec *>(timeout));
8155 548648 return ret;
8156 548648 }
8157
8158 /**
8159 Close the log file.
8160
8161 @param exiting Bitmask for one or more of the following bits:
8162 - LOG_CLOSE_INDEX : if we should close the index file
8163 - LOG_CLOSE_TO_BE_OPENED : if we intend to call open
8164 at once after close.
8165 - LOG_CLOSE_STOP_EVENT : write a 'stop' event to the log
8166
8167 @param need_lock_log If true, this function acquires LOCK_log;
8168 otherwise the caller should already have acquired it.
8169
8170 @param need_lock_index If true, this function acquires LOCK_index;
8171 otherwise the caller should already have acquired it.
8172
8173 @note
8174 One can do an open on the object at once after doing a close.
8175 The internal structures are not freed until cleanup() is called
8176 */
8177
8178 128341 void MYSQL_BIN_LOG::close(
8179 uint exiting, bool need_lock_log,
8180 bool need_lock_index) { // One can't set log_type here!
8181
1/2
✓ Branch 0 taken 128342 times.
✗ Branch 1 not taken.
128341 DBUG_TRACE;
8182
5/8
✓ Branch 0 taken 128341 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 128342 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 128341 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
128342 DBUG_PRINT("enter", ("exiting: %d", (int)exiting));
8183
2/2
✓ Branch 0 taken 38258 times.
✓ Branch 1 taken 90084 times.
128342 if (need_lock_log)
8184
1/2
✓ Branch 0 taken 38258 times.
✗ Branch 1 not taken.
38258 mysql_mutex_lock(&LOCK_log);
8185 else
8186 mysql_mutex_assert_owner(&LOCK_log);
8187
8188
2/2
✓ Branch 0 taken 77244 times.
✓ Branch 1 taken 51098 times.
128342 if (atomic_log_state == LOG_OPENED) {
8189
2/2
✓ Branch 0 taken 16324 times.
✓ Branch 1 taken 60920 times.
77244 if ((exiting & LOG_CLOSE_STOP_EVENT) != 0) {
8190 /**
8191 TODO(WL#7546): Change the implementation to Stop_event after write() is
8192 moved into libbinlogevents
8193 */
8194
1/2
✓ Branch 0 taken 16324 times.
✗ Branch 1 not taken.
16324 Stop_log_event s;
8195 // the checksumming rule for relay-log case is similar to Rotate
8196 16324 s.common_footer->checksum_alg =
8197 16324 is_relay_log
8198
2/2
✓ Branch 0 taken 8598 times.
✓ Branch 1 taken 7726 times.
16324 ? relay_log_checksum_alg
8199 7726 : static_cast<enum_binlog_checksum_alg>(binlog_checksum_options);
8200
3/4
✓ Branch 0 taken 8598 times.
✓ Branch 1 taken 7726 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8598 times.
16324 assert(!is_relay_log ||
8201 relay_log_checksum_alg != binary_log::BINLOG_CHECKSUM_ALG_UNDEF);
8202
7/10
✓ Branch 0 taken 16324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16324 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16324 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 16322 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 16322 times.
✓ Branch 9 taken 2 times.
16324 if (!write_event_to_binlog(&s) && !m_binlog_file->flush())
8203
1/2
✓ Branch 0 taken 16322 times.
✗ Branch 1 not taken.
16322 update_binlog_end_pos();
8204 16324 }
8205
8206 /* The following update should not be done in relay log files */
8207
2/2
✓ Branch 0 taken 24861 times.
✓ Branch 1 taken 52383 times.
77244 if (!is_relay_log) {
8208 24861 my_off_t offset = BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
8209 24861 uchar flags = 0; // clearing LOG_EVENT_BINLOG_IN_USE_F
8210
1/2
✓ Branch 0 taken 24861 times.
✗ Branch 1 not taken.
24861 (void)m_binlog_file->update(&flags, 1, offset);
8211 }
8212
8213
6/8
✓ Branch 0 taken 77241 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 77239 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 77239 times.
77244 if (m_binlog_file->flush_and_sync() && !write_error) {
8214
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 report_binlog_write_error();
8215 }
8216
8217 /*
8218 LOCK_sync to guarantee that no thread is calling m_binlog_file
8219 to sync data to disk when another thread is closing m_binlog_file.
8220 */
8221
3/4
✓ Branch 0 taken 24861 times.
✓ Branch 1 taken 52380 times.
✓ Branch 2 taken 24861 times.
✗ Branch 3 not taken.
77241 if (!is_relay_log) mysql_mutex_lock(&LOCK_sync);
8222 77241 m_binlog_file->close();
8223
3/4
✓ Branch 0 taken 24861 times.
✓ Branch 1 taken 52383 times.
✓ Branch 2 taken 24861 times.
✗ Branch 3 not taken.
77244 if (!is_relay_log) mysql_mutex_unlock(&LOCK_sync);
8224
8225 77244 atomic_log_state =
8226
2/2
✓ Branch 0 taken 60898 times.
✓ Branch 1 taken 16346 times.
77244 (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
8227
1/2
✓ Branch 0 taken 77244 times.
✗ Branch 1 not taken.
77244 my_free(name);
8228 77244 name = nullptr;
8229 }
8230
8231 /*
8232 The following test is needed even if is_open() is not set, as we may have
8233 called a not complete close earlier and the index file is still open.
8234 */
8235
8236
2/2
✓ Branch 0 taken 38272 times.
✓ Branch 1 taken 90070 times.
128342 if (need_lock_index)
8237
1/2
✓ Branch 0 taken 38272 times.
✗ Branch 1 not taken.
38272 mysql_mutex_lock(&LOCK_index);
8238 else
8239 mysql_mutex_assert_owner(&LOCK_index);
8240
8241
6/6
✓ Branch 0 taken 99200 times.
✓ Branch 1 taken 29142 times.
✓ Branch 2 taken 77457 times.
✓ Branch 3 taken 21743 times.
✓ Branch 4 taken 77457 times.
✓ Branch 5 taken 50885 times.
128342 if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file)) {
8242
1/2
✓ Branch 0 taken 77457 times.
✗ Branch 1 not taken.
77457 end_io_cache(&index_file);
8243
6/8
✓ Branch 0 taken 77457 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 77455 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 77455 times.
77457 if (mysql_file_close(index_file.file, MYF(0)) < 0 && !write_error) {
8244
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 report_binlog_write_error();
8245 }
8246 }
8247
8248
3/4
✓ Branch 0 taken 38272 times.
✓ Branch 1 taken 90070 times.
✓ Branch 2 taken 38272 times.
✗ Branch 3 not taken.
128342 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
8249
8250 128342 atomic_log_state =
8251
2/2
✓ Branch 0 taken 90040 times.
✓ Branch 1 taken 38302 times.
128342 (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
8252
1/2
✓ Branch 0 taken 128342 times.
✗ Branch 1 not taken.
128342 my_free(name);
8253 128342 name = nullptr;
8254
8255
3/4
✓ Branch 0 taken 38258 times.
✓ Branch 1 taken 90084 times.
✓ Branch 2 taken 38258 times.
✗ Branch 3 not taken.
128342 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
8256 128342 }
8257
8258 1591671 void MYSQL_BIN_LOG::harvest_bytes_written(Relay_log_info *rli,
8259 bool need_log_space_lock) {
8260 #ifndef NDEBUG
8261 char buf1[22], buf2[22];
8262 #endif
8263
8264
1/2
✓ Branch 0 taken 1591671 times.
✗ Branch 1 not taken.
1591671 DBUG_TRACE;
8265
2/2
✓ Branch 0 taken 1591646 times.
✓ Branch 1 taken 25 times.
1591671 if (need_log_space_lock)
8266
1/2
✓ Branch 0 taken 1591646 times.
✗ Branch 1 not taken.
1591646 mysql_mutex_lock(&rli->log_space_lock);
8267 else
8268 mysql_mutex_assert_owner(&rli->log_space_lock);
8269 1591671 rli->log_space_total += bytes_written;
8270
3/12
✓ Branch 0 taken 1591671 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1591671 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1591671 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
1591671 DBUG_PRINT("info",
8271 ("relay_log_space: %s bytes_written: %s",
8272 llstr(rli->log_space_total, buf1), llstr(bytes_written, buf2)));
8273 1591671 bytes_written = 0;
8274
3/4
✓ Branch 0 taken 1591646 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 1591645 times.
✗ Branch 3 not taken.
1591671 if (need_log_space_lock) mysql_mutex_unlock(&rli->log_space_lock);
8275 1591670 }
8276
8277 213 void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg) {
8278 /*
8279 We need to take locks, otherwise this may happen:
8280 new_file() is called, calls open(old_max_size), then before open() starts,
8281 set_max_size() sets max_size to max_size_arg, then open() starts and
8282 uses the old_max_size argument, so max_size_arg has been overwritten and
8283 it's like if the SET command was never run.
8284 */
8285
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213 DBUG_TRACE;
8286
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213 mysql_mutex_lock(&LOCK_log);
8287
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 103 times.
213 if (is_open()) max_size = max_size_arg;
8288
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213 mysql_mutex_unlock(&LOCK_log);
8289 213 }
8290
8291 /****** transaction coordinator log for 2pc - binlog() based solution ******/
8292
8293 /**
8294 @todo
8295 keep in-memory list of prepared transactions
8296 (add to list in log(), remove on unlog())
8297 and copy it to the new binlog if rotated
8298 but let's check the behaviour of tc_log_page_waits first!
8299 */
8300
8301 9109 int MYSQL_BIN_LOG::open_binlog(const char *opt_name) {
8302 9109 LOG_INFO log_info;
8303 9109 int error = 1;
8304 9109 bool should_execute_ha_recover{false};
8305
8306 /*
8307 This function is used for 2pc transaction coordination. Hence, it
8308 is never used for relay logs.
8309 */
8310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9109 times.
9109 assert(!is_relay_log);
8311
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 9109 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
9109 assert(total_ha_2pc > 1 || (1 == total_ha_2pc && opt_bin_log));
8312
2/4
✓ Branch 0 taken 9109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9109 times.
✗ Branch 3 not taken.
9109 assert(opt_name && opt_name[0]);
8313
8314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9109 times.
9109 if (!my_b_inited(&index_file)) {
8315 /* There was a failure to open the index file, can't open the binlog */
8316 cleanup();
8317 return 1;
8318 }
8319
8320
3/4
✓ Branch 0 taken 9109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9107 times.
9109 if (using_heuristic_recover()) {
8321 /* generate a new binlog to mask a corrupted one */
8322
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mysql_mutex_lock(&LOCK_log);
8323
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 open_binlog(opt_name, nullptr, max_binlog_size, false,
8324 true /*need_lock_index=true*/, true /*need_sid_lock=true*/,
8325 nullptr);
8326
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mysql_mutex_unlock(&LOCK_log);
8327
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 cleanup();
8328 2 return 1;
8329 }
8330
8331
3/4
✓ Branch 0 taken 9107 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4189 times.
✓ Branch 3 taken 4918 times.
9107 if ((error = find_log_pos(&log_info, NullS, true /*need_lock_index=true*/))) {
8332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4189 times.
4189 if (error != LOG_INFO_EOF)
8333 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_FIND_LOG_IN_INDEX, error);
8334 else {
8335 4189 error = 0;
8336 4189 should_execute_ha_recover = true;
8337 }
8338 4189 goto err;
8339 }
8340
8341 {
8342 4918 Log_event *ev = nullptr;
8343 char log_name[FN_REFLEN];
8344 4918 my_off_t valid_pos = 0;
8345 4918 my_off_t binlog_size = 0;
8346
8347 do {
8348
1/2
✓ Branch 0 taken 217497 times.
✗ Branch 1 not taken.
217497 strmake(log_name, log_info.log_file_name, sizeof(log_name) - 1);
8349 } while (
8350
3/4
✓ Branch 0 taken 217497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212579 times.
✓ Branch 3 taken 4918 times.
217497 !(error = find_next_log(&log_info, true /*need_lock_index=true*/)));
8351
8352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4918 times.
4918 if (error != LOG_INFO_EOF) {
8353 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_FIND_LOG_IN_INDEX, error);
8354 3177 goto err;
8355 }
8356
8357
1/2
✓ Branch 0 taken 4918 times.
✗ Branch 1 not taken.
4918 Binlog_file_reader binlog_file_reader(opt_source_verify_checksum);
8358
3/4
✓ Branch 0 taken 4918 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4905 times.
4918 if (binlog_file_reader.open(log_name)) {
8359
9/18
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 13 times.
✗ Branch 17 not taken.
13 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_OPEN_FAILED,
8360 binlog_file_reader.get_error_str());
8361 13 goto err;
8362 }
8363
8364 /*
8365 If the binary log was not properly closed it means that the server
8366 may have crashed. In that case, we need to call
8367 binlog::Binlog_recovery::recover()
8368 to:
8369
8370 a) collect logged XIDs;
8371 b) complete the 2PC of the pending XIDs;
8372 c) collect the last valid position.
8373
8374 Therefore, we do need to iterate over the binary log, even if
8375 total_ha_2pc == 1, to find the last valid group of events written.
8376 Later we will take this value and truncate the log if need be.
8377 */
8378
2/4
✓ Branch 0 taken 4905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4905 times.
✗ Branch 3 not taken.
9810 if ((ev = binlog_file_reader.read_event_object()) &&
8379
3/4
✓ Branch 0 taken 4905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1807 times.
✓ Branch 3 taken 3098 times.
9810 ev->get_type_code() == binary_log::FORMAT_DESCRIPTION_EVENT &&
8380
2/2
✓ Branch 0 taken 3098 times.
✓ Branch 1 taken 1807 times.
4905 (ev->common_header->flags & LOG_EVENT_BINLOG_IN_USE_F ||
8381
2/4
✓ Branch 0 taken 3098 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3098 times.
3098 DBUG_EVALUATE_IF("eval_force_bin_log_recovery", true, false))) {
8382
8/16
✓ Branch 0 taken 1807 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1807 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1807 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1807 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1807 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1807 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1807 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1807 times.
✗ Branch 15 not taken.
1807 LogErr(INFORMATION_LEVEL, ER_BINLOG_RECOVERING_AFTER_CRASH_USING,
8383 opt_name);
8384
1/2
✓ Branch 0 taken 1807 times.
✗ Branch 1 not taken.
1807 binlog::Binlog_recovery bl_recovery{binlog_file_reader};
8385 1807 error = bl_recovery //
8386
1/2
✓ Branch 0 taken 1807 times.
✗ Branch 1 not taken.
1807 .recover() //
8387
1/2
✓ Branch 0 taken 1807 times.
✗ Branch 1 not taken.
1807 .has_failures();
8388
1/2
✓ Branch 0 taken 1807 times.
✗ Branch 1 not taken.
1807 valid_pos = bl_recovery.get_valid_pos();
8389
1/2
✓ Branch 0 taken 1807 times.
✗ Branch 1 not taken.
1807 binlog_size = binlog_file_reader.ifile()->length();
8390
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 1741 times.
1807 if (error) {
8391
3/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 48 times.
66 if (bl_recovery.is_binlog_malformed())
8392
9/18
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 18 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 18 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 18 times.
✗ Branch 17 not taken.
18 LogErr(ERROR_LEVEL, ER_BINLOG_CRASH_RECOVERY_MALFORMED_LOG, log_name,
8393 valid_pos, binlog_file_reader.position(),
8394 bl_recovery.get_failure_message().data());
8395
3/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 18 times.
66 if (bl_recovery.has_engine_recovery_failed())
8396
8/16
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 48 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 48 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 48 times.
✗ Branch 15 not taken.
48 LogErr(ERROR_LEVEL, ER_BINLOG_CRASH_RECOVERY_ERROR_RETURNED_SE);
8397 }
8398 1807 } else
8399 3098 should_execute_ha_recover = true;
8400
8401
1/2
✓ Branch 0 taken 4905 times.
✗ Branch 1 not taken.
4905 delete ev;
8402
8403
2/2
✓ Branch 0 taken 3164 times.
✓ Branch 1 taken 1741 times.
4905 if (error) goto err;
8404
8405 /* Trim the crashed binlog file to last valid transaction
8406 or event (non-transaction) base on valid_pos. */
8407
1/2
✓ Branch 0 taken 1741 times.
✗ Branch 1 not taken.
1741 if (valid_pos > 0) {
8408 std::unique_ptr<Binlog_ofile> ofile(
8409
1/2
✓ Branch 0 taken 1741 times.
✗ Branch 1 not taken.
1741 Binlog_ofile::open_existing(key_file_binlog, log_name, MYF(MY_WME)));
8410
8411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1741 times.
1741 if (!ofile) {
8412 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_CRASHED_BINLOG);
8413 return -1;
8414 }
8415
8416 /* Change binlog file size to valid_pos */
8417
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1735 times.
1741 if (valid_pos < binlog_size) {
8418
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (ofile->truncate(valid_pos)) {
8419 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_TRIM_CRASHED_BINLOG);
8420 return -1;
8421 }
8422
8/16
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
6 LogErr(INFORMATION_LEVEL, ER_BINLOG_CRASHED_BINLOG_TRIMMED, log_name,
8423 binlog_size, valid_pos, valid_pos);
8424 }
8425
8426 /* Clear LOG_EVENT_BINLOG_IN_USE_F */
8427 1741 uchar flags = 0;
8428
2/4
✓ Branch 0 taken 1741 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1741 times.
1741 if (ofile->update(&flags, 1, BIN_LOG_HEADER_SIZE + FLAGS_OFFSET)) {
8429 LogErr(ERROR_LEVEL,
8430 ER_BINLOG_CANT_CLEAR_IN_USE_FLAG_FOR_CRASHED_BINLOG);
8431 return -1;
8432 }
8433
1/2
✓ Branch 0 taken 1741 times.
✗ Branch 1 not taken.
1741 } // end if (valid_pos > 0)
8434
2/3
✓ Branch 0 taken 1741 times.
✓ Branch 1 taken 3177 times.
✗ Branch 2 not taken.
4918 }
8435
8436 9107 err:
8437
2/2
✓ Branch 0 taken 7287 times.
✓ Branch 1 taken 1820 times.
9107 if (should_execute_ha_recover) {
8438
1/2
✓ Branch 0 taken 7287 times.
✗ Branch 1 not taken.
7287 error = ha_recover();
8439
1/18
✗ Branch 0 not taken.
✓ Branch 1 taken 7287 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
7287 if (error) LogErr(ERROR_LEVEL, ER_BINLOG_CRASH_RECOVERY_ERROR_RETURNED_SE);
8440 }
8441 9107 return error;
8442 }
8443
8444 /**
8445 Truncate the active relay log file in the specified position.
8446
8447 @param mi Master_info of the channel going to truncate the relay log file.
8448 @param truncate_pos The position to truncate the active relay log file.
8449 @return False on success and true on failure.
8450 */
8451 6 bool MYSQL_BIN_LOG::truncate_relaylog_file(Master_info *mi,
8452 my_off_t truncate_pos) {
8453
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_TRACE;
8454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(is_relay_log);
8455 mysql_mutex_assert_owner(&LOCK_log);
8456 6 Relay_log_info *rli = mi->rli;
8457 6 bool error = false;
8458
8459 /*
8460 If the relay log was closed by an error (binlog_error_action=IGNORE_ERROR)
8461 this truncate function should produce no result as the relay log is already
8462 in really bad shape.
8463 */
8464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!is_open()) {
8465 return false;
8466 }
8467
8468 6 my_off_t relaylog_file_size = m_binlog_file->position();
8469
8470
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (truncate_pos > 0 && truncate_pos < relaylog_file_size) {
8471
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (m_binlog_file->truncate(truncate_pos)) {
8472 mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
8473 ER_THD(current_thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
8474 "failed to truncate relay log file");
8475 error = true;
8476 } else {
8477
8/16
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
6 LogErr(INFORMATION_LEVEL, ER_SLAVE_RELAY_LOG_TRUNCATE_INFO, log_file_name,
8478 relaylog_file_size, truncate_pos);
8479
8480 // Re-init the SQL thread IO_CACHE
8481
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 assert(strcmp(rli->get_event_relay_log_name(), log_file_name) ||
8482 rli->get_event_relay_log_pos() <= truncate_pos);
8483
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 rli->notify_relay_log_truncated();
8484 }
8485 }
8486 6 return error;
8487 6 }
8488
8489 /** This is called on shutdown, after ha_panic. */
8490 void MYSQL_BIN_LOG::close() {}
8491
8492 /*
8493 Prepare the transaction in the transaction coordinator.
8494
8495 This function will prepare the transaction in the storage engines
8496 (by calling @c ha_prepare_low) what will write a prepare record
8497 to the log buffers.
8498
8499 @retval 0 success
8500 @retval 1 error
8501 */
8502 4974096 int MYSQL_BIN_LOG::prepare(THD *thd, bool all) {
8503
1/2
✓ Branch 0 taken 4974163 times.
✗ Branch 1 not taken.
4974096 DBUG_TRACE;
8504
8505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4974163 times.
4974163 assert(opt_bin_log);
8506
8507 /*
8508 Set HA_IGNORE_DURABILITY to not flush the prepared record of the
8509 transaction to the log of storage engine (for example, InnoDB
8510 redo log) during the prepare phase. So that we can flush prepared
8511 records of transactions to the log of storage engine in a group
8512 right before flushing them to binary log during binlog group
8513 commit flush stage. Reset to HA_REGULAR_DURABILITY at the
8514 beginning of parsing next command.
8515 */
8516 4974163 thd->durability_property = HA_IGNORE_DURABILITY;
8517
8518
2/4
✓ Branch 0 taken 4974154 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4974169 times.
✗ Branch 3 not taken.
4974163 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_prepare_in_engines");
8519
1/2
✓ Branch 0 taken 4974122 times.
✗ Branch 1 not taken.
4974176 int error = ha_prepare_low(thd, all);
8520
8521
2/4
✓ Branch 0 taken 4974157 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4974157 times.
✗ Branch 3 not taken.
4974122 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("after_ha_prepare_low");
8522 // Invoke `commit` if we're dealing with `XA PREPARE` in order to use BCG
8523 // to write the event to file.
8524
10/12
✓ Branch 0 taken 4973830 times.
✓ Branch 1 taken 308 times.
✓ Branch 2 taken 536650 times.
✓ Branch 3 taken 4437180 times.
✓ Branch 4 taken 536648 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 574 times.
✓ Branch 7 taken 536074 times.
✓ Branch 8 taken 574 times.
✓ Branch 9 taken 4973562 times.
✓ Branch 10 taken 571 times.
✗ Branch 11 not taken.
4974138 if (!error && all && is_xa_prepare(thd)) return this->commit(thd, true);
8525
8526 4973562 return error;
8527 4974133 }
8528
8529 /**
8530 Commit the transaction in the transaction coordinator.
8531
8532 This function will commit the sessions transaction in the binary log
8533 and in the storage engines (by calling @c ha_commit_low). If the
8534 transaction was successfully logged (or not successfully unlogged)
8535 but the commit in the engines did not succeed, there is a risk of
8536 inconsistency between the engines and the binary log.
8537
8538 For binary log group commit, the commit is separated into three
8539 parts:
8540
8541 1. First part consists of filling the necessary caches and
8542 finalizing them (if they need to be finalized). After this,
8543 nothing is added to any of the caches.
8544
8545 2. Second part execute an ordered flush and commit. This will be
8546 done using the group commit functionality in ordered_commit.
8547
8548 3. Third part checks any errors resulting from the ordered commit
8549 and handles them appropriately.
8550
8551 @retval RESULT_SUCCESS success
8552 @retval RESULT_ABORTED error, transaction was neither logged nor committed
8553 @retval RESULT_INCONSISTENT error, transaction was logged but not committed
8554 */
8555 31168391 TC_LOG::enum_result MYSQL_BIN_LOG::commit(THD *thd, bool all) {
8556
1/2
✓ Branch 0 taken 31173630 times.
✗ Branch 1 not taken.
31168391 DBUG_TRACE;
8557
8/14
✓ Branch 0 taken 31172217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31172816 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 636 times.
✓ Branch 5 taken 31172180 times.
✓ Branch 6 taken 636 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 636 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 636 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 636 times.
✗ Branch 13 not taken.
31173630 DBUG_PRINT("info",
8558 ("query='%s'", thd == current_thd ? thd->query().str : nullptr));
8559 31172816 Transaction_ctx *trn_ctx = thd->get_transaction();
8560 #ifdef WITH_WSREP
8561 my_xid xid;
8562 31170918 const XID *curr_xid = trn_ctx->xid_state()->get_xid();
8563
3/4
✓ Branch 0 taken 31169905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 267649 times.
✓ Branch 3 taken 30902256 times.
31170609 if (wsrep_is_wsrep_xid(curr_xid)) {
8564
1/2
✓ Branch 0 taken 267658 times.
✗ Branch 1 not taken.
267649 xid = wsrep_xid_seqno(*curr_xid).get();
8565 } else {
8566
1/2
✓ Branch 0 taken 30903241 times.
✗ Branch 1 not taken.
30902256 xid = curr_xid->get_my_xid();
8567 }
8568 #else
8569 my_xid xid = trn_ctx->xid_state()->get_xid()->get_my_xid();
8570 #endif /* WITH_WSREP */
8571 31170902 bool stmt_stuff_logged = false;
8572 31170902 bool trx_stuff_logged = false;
8573
1/2
✓ Branch 0 taken 31171526 times.
✗ Branch 1 not taken.
31170902 bool skip_commit = is_loggable_xa_prepare(thd);
8574 31171526 bool is_atomic_ddl = false;
8575 31171526 auto xs = thd->get_transaction()->xid_state();
8576 31168567 raii::Sentry<> reset_detached_guard{[&]() -> void {
8577 // XID_STATE may have been used to hold metadata for a detached transaction.
8578 // In that case, we need to reset it.
8579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31169504 times.
31168567 if (xs->is_detached()) xs->reset();
8580
1/2
✓ Branch 0 taken 31170377 times.
✗ Branch 1 not taken.
31171887 }};
8581
8582
2/2
✓ Branch 0 taken 1086 times.
✓ Branch 1 taken 31169411 times.
31170497 if (thd->lex->sql_command ==
8583 SQLCOM_XA_COMMIT) { // XA commit must be written to the binary log prior
8584 // to retrieving cache manager
8585
2/4
✓ Branch 0 taken 1086 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1086 times.
1086 if (this->write_xa_to_cache(thd)) return RESULT_ABORTED;
8586 }
8587
8588
1/2
✓ Branch 0 taken 31170915 times.
✗ Branch 1 not taken.
31170497 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
8589
7/10
✓ Branch 0 taken 31170423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31170877 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 628 times.
✓ Branch 5 taken 31170249 times.
✓ Branch 6 taken 300 times.
✓ Branch 7 taken 328 times.
✓ Branch 8 taken 703 times.
✗ Branch 9 not taken.
31170915 DBUG_PRINT("enter", ("thd: 0x%llx, all: %s, xid: %llu, cache_mngr: 0x%llx",
8590 (ulonglong)thd, YESNO(all), (ulonglong)xid,
8591 (ulonglong)cache_mngr));
8592
8593 /*
8594 No cache manager means nothing to log, but we still have to commit
8595 the transaction.
8596 */
8597
2/2
✓ Branch 0 taken 10545523 times.
✓ Branch 1 taken 20625429 times.
31170952 if (cache_mngr == nullptr) {
8598
7/8
✓ Branch 0 taken 10545422 times.
✓ Branch 1 taken 101 times.
✓ Branch 2 taken 10546077 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 10546074 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 10546175 times.
10545523 if (!skip_commit && trx_coordinator::commit_in_engines(thd, all))
8599 3 return RESULT_ABORTED;
8600 10546175 return RESULT_SUCCESS;
8601 }
8602
8603 /*
8604 Reset binlog_snapshot_% variables for the current connection so that the
8605 current coordinates are shown after committing a consistent snapshot
8606 transaction.
8607 */
8608
2/2
✓ Branch 0 taken 2032173 times.
✓ Branch 1 taken 18593256 times.
20625429 if (all) {
8609
1/2
✓ Branch 0 taken 2032241 times.
✗ Branch 1 not taken.
2032173 mysql_mutex_lock(&thd->LOCK_thd_data);
8610 2032241 cache_mngr->drop_consistent_snapshot();
8611
1/2
✓ Branch 0 taken 2032207 times.
✗ Branch 1 not taken.
2032345 mysql_mutex_unlock(&thd->LOCK_thd_data);
8612 }
8613
8614 20625463 Transaction_ctx::enum_trx_scope trx_scope =
8615
2/2
✓ Branch 0 taken 2032391 times.
✓ Branch 1 taken 18593072 times.
20625463 all ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
8616
8617
8/12
✓ Branch 0 taken 20625688 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20625894 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 616 times.
✓ Branch 5 taken 20625278 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 616 times.
✓ Branch 8 taken 583 times.
✓ Branch 9 taken 33 times.
✓ Branch 10 taken 616 times.
✗ Branch 11 not taken.
20625463 DBUG_PRINT("debug", ("in_transaction: %s, no_2pc: %s, rw_ha_count: %d",
8618 YESNO(thd->in_multi_stmt_transaction_mode()),
8619 YESNO(trn_ctx->no_2pc(trx_scope)),
8620 trn_ctx->rw_ha_count(trx_scope)));
8621
10/14
✓ Branch 0 taken 20625579 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20625818 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 616 times.
✓ Branch 5 taken 20625202 times.
✓ Branch 6 taken 616 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 437 times.
✓ Branch 9 taken 179 times.
✓ Branch 10 taken 24 times.
✓ Branch 11 taken 592 times.
✓ Branch 12 taken 616 times.
✗ Branch 13 not taken.
20625894 DBUG_PRINT("debug",
8622 ("all.cannot_safely_rollback(): %s, trx_cache_empty: %s",
8623 YESNO(trn_ctx->cannot_safely_rollback(Transaction_ctx::SESSION)),
8624 YESNO(cache_mngr->trx_cache.is_binlog_empty())));
8625
9/14
✓ Branch 0 taken 20625608 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20625859 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 616 times.
✓ Branch 5 taken 20625243 times.
✓ Branch 6 taken 616 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 591 times.
✓ Branch 9 taken 25 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 606 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
20625818 DBUG_PRINT("debug",
8626 ("stmt.cannot_safely_rollback(): %s, stmt_cache_empty: %s",
8627 YESNO(trn_ctx->cannot_safely_rollback(Transaction_ctx::STMT)),
8628 YESNO(cache_mngr->stmt_cache.is_binlog_empty())));
8629
8630 /*
8631 If there are no handlertons registered, there is nothing to
8632 commit. Note that DDLs are written earlier in this case (inside
8633 binlog_query).
8634
8635 TODO: This can be a problem in those cases that there are no
8636 handlertons registered. DDLs are one example, but the other case
8637 is MyISAM. In this case, we could register a dummy handlerton to
8638 trigger the commit.
8639
8640 Any statement that requires logging will call binlog_query before
8641 trans_commit_stmt, so an alternative is to use the condition
8642 "binlog_query called or stmt.ha_list != 0".
8643 */
8644
6/6
✓ Branch 0 taken 18592893 times.
✓ Branch 1 taken 2032186 times.
✓ Branch 2 taken 12772973 times.
✓ Branch 3 taken 5820198 times.
✓ Branch 4 taken 12687540 times.
✓ Branch 5 taken 7938456 times.
33398691 if (!all && !trn_ctx->is_active(trx_scope) &&
8645
3/4
✓ Branch 0 taken 12773612 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12687516 times.
✓ Branch 3 taken 86096 times.
12772973 cache_mngr->stmt_cache.is_binlog_empty())
8646 12687540 return RESULT_SUCCESS;
8647
8648
3/4
✓ Branch 0 taken 7938632 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 489226 times.
✓ Branch 3 taken 7449406 times.
7938456 if (!cache_mngr->stmt_cache.is_binlog_empty()) {
8649 /*
8650 Commit parent identification of non-transactional query has
8651 been deferred until now, except for the mixed transaction case.
8652 */
8653
1/2
✓ Branch 0 taken 489122 times.
✗ Branch 1 not taken.
489226 trn_ctx->store_commit_parent(
8654 m_dependency_tracker.get_max_committed_timestamp());
8655
2/4
✓ Branch 0 taken 489311 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 489311 times.
489083 if (cache_mngr->stmt_cache.finalize(thd)) return RESULT_ABORTED;
8656 489311 stmt_stuff_logged = true;
8657 }
8658
8659 /*
8660 We commit the transaction if:
8661 - We are not in a transaction and committing a statement, or
8662 - We are in a transaction and a full transaction is committed.
8663 Otherwise, we accumulate the changes.
8664 */
8665
8/10
✓ Branch 0 taken 7938702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5225048 times.
✓ Branch 3 taken 2713654 times.
✓ Branch 4 taken 5225021 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2100573 times.
✓ Branch 7 taken 3124448 times.
✓ Branch 8 taken 2100573 times.
✓ Branch 9 taken 5838102 times.
10039290 if (!cache_mngr->trx_cache.is_binlog_empty() && ending_trans(thd, all) &&
8666
2/2
✓ Branch 0 taken 2100572 times.
✓ Branch 1 taken 1 times.
2100573 !trx_stuff_logged) {
8667 const bool real_trans =
8668
3/4
✓ Branch 0 taken 1509662 times.
✓ Branch 1 taken 590911 times.
✓ Branch 2 taken 1509662 times.
✗ Branch 3 not taken.
2100573 (all || !trn_ctx->is_active(Transaction_ctx::SESSION));
8669
8670
1/2
✓ Branch 0 taken 2100568 times.
✗ Branch 1 not taken.
2100573 bool one_phase = get_xa_opt(thd) == XA_ONE_PHASE;
8671
1/2
✓ Branch 0 taken 2100577 times.
✗ Branch 1 not taken.
2100568 bool is_loggable_xa = is_loggable_xa_prepare(thd);
8672
8673 /*
8674 Log and finalize transaction cache regarding XA PREPARE/XA COMMIT ONE
8675 PHASE if one of the following statements is true:
8676 - If it is a loggable XA transaction in prepare state;
8677 - If it is a transaction being committed with 'XA COMMIT ONE PHASE',
8678 statement and is not an empty transaction when GTID_NEXT is set to a
8679 manual GTID.
8680
8681 For other XA COMMIT ONE PHASE statements that already have been finalized
8682 or are finalizing empty transactions when GTID_NEXT is set to a manual
8683 GTID, just let the execution flow get into the final 'else' branch and log
8684 a final 'COMMIT;' statement.
8685 */
8686
4/4
✓ Branch 0 taken 2100038 times.
✓ Branch 1 taken 539 times.
✓ Branch 2 taken 638 times.
✓ Branch 3 taken 2099939 times.
4200615 if (is_loggable_xa || // XA transaction in prepare state
8687
3/4
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 2099936 times.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
2100038 (thd->lex->sql_command == SQLCOM_XA_COMMIT && // Is a 'XA COMMIT
8688 102 one_phase && // ONE PHASE'
8689
1/2
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
102 xs != nullptr && // and it has not yet
8690
1/2
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
102 !xs->is_binlogged() && // been logged
8691
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 87 times.
102 (thd->owned_gtid.sidno <= 0 || // and GTID_NEXT is NOT set to a
8692 // manual GTID
8693
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
15 !xs->has_state(XID_STATE::XA_NOTR)))) // and the transaction is NOT
8694 // empty and NOT finalized in
8695 // 'trans_xa_commit'
8696 {
8697 /* The prepare phase of XA transaction two phase logging. */
8698 638 int err = 0;
8699
8700
3/4
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 539 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 99 times.
638 assert(thd->lex->sql_command != SQLCOM_XA_COMMIT || one_phase);
8701
8702
1/2
✓ Branch 0 taken 638 times.
✗ Branch 1 not taken.
638 XA_prepare_log_event end_evt(thd, xs->get_xid(), one_phase);
8703
8704
3/4
✓ Branch 0 taken 539 times.
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 539 times.
638 assert(!is_loggable_xa || skip_commit);
8705
8706
1/2
✓ Branch 0 taken 638 times.
✗ Branch 1 not taken.
638 err = cache_mngr->trx_cache.finalize(thd, &end_evt, xs);
8707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 if (err) return RESULT_ABORTED;
8708
2/2
✓ Branch 0 taken 539 times.
✓ Branch 1 taken 99 times.
638 if (is_loggable_xa)
8709
3/4
✓ Branch 0 taken 539 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 533 times.
539 if (DBUG_EVALUATE_IF("simulate_xa_prepare_failure_in_cache_finalize",
8710 true, false))
8711 6 return RESULT_ABORTED;
8712
2/2
✓ Branch 0 taken 632 times.
✓ Branch 1 taken 6 times.
638 }
8713 /*
8714 If is atomic DDL, finalize cache for DDL and no further logging is needed.
8715 */
8716
2/2
✓ Branch 0 taken 317939 times.
✓ Branch 1 taken 1781994 times.
2099939 else if ((is_atomic_ddl = cache_mngr->trx_cache.has_xid())) {
8717
2/4
✓ Branch 0 taken 317939 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 317939 times.
317939 if (cache_mngr->trx_cache.finalize(thd, nullptr)) return RESULT_ABORTED;
8718 }
8719 /*
8720 We are committing a 2PC transaction if it is a "real" transaction
8721 and has an XID assigned (because some handlerton registered). A
8722 transaction is "real" if either 'all' is true or
8723 'trn_ctx->is_active(Transaction_ctx::SESSION)' is not true.
8724
8725 Note: This is kind of strange since registering the binlog
8726 handlerton will then make the transaction 2PC, which is not really
8727 true. This occurs for example if a MyISAM statement is executed
8728 with row-based replication on.
8729 */
8730
8/8
✓ Branch 0 taken 1781990 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1751905 times.
✓ Branch 3 taken 30085 times.
✓ Branch 4 taken 1722016 times.
✓ Branch 5 taken 29892 times.
✓ Branch 6 taken 1722014 times.
✓ Branch 7 taken 59983 times.
3504010 else if (real_trans && xid && trn_ctx->rw_ha_count(trx_scope) > 1 &&
8731
1/2
✓ Branch 0 taken 1722017 times.
✗ Branch 1 not taken.
1722016 !trn_ctx->no_2pc(trx_scope)) {
8732
1/2
✓ Branch 0 taken 1722013 times.
✗ Branch 1 not taken.
1722014 Xid_log_event end_evt(thd, xid);
8733
2/4
✓ Branch 0 taken 1722021 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1722021 times.
1722013 if (cache_mngr->trx_cache.finalize(thd, &end_evt)) return RESULT_ABORTED;
8734
1/2
✓ Branch 0 taken 1722005 times.
✗ Branch 1 not taken.
1722021 }
8735 /*
8736 No further action needed and no special case applies, log a final
8737 'COMMIT' statement and finalize the transaction cache.
8738
8739 Empty transactions finalized with 'XA COMMIT ONE PHASE' will be covered
8740 by this branch.
8741 */
8742 else {
8743 Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"), true, false, true,
8744
1/2
✓ Branch 0 taken 59980 times.
✗ Branch 1 not taken.
59983 0, true);
8745
2/4
✓ Branch 0 taken 59980 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59980 times.
59980 if (cache_mngr->trx_cache.finalize(thd, &end_evt)) return RESULT_ABORTED;
8746
1/2
✓ Branch 0 taken 59980 times.
✗ Branch 1 not taken.
59980 }
8747 2100556 trx_stuff_logged = true;
8748 }
8749
8750 /*
8751 This is part of the stmt rollback.
8752 */
8753
3/4
✓ Branch 0 taken 5906098 times.
✓ Branch 1 taken 2032560 times.
✓ Branch 2 taken 5906433 times.
✗ Branch 3 not taken.
7938658 if (!all) cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
8754
8755 /*
8756 Now all the events are written to the caches, so we will commit
8757 the transaction in the engines. This is done using the group
8758 commit logic in ordered_commit, which will return when the
8759 transaction is committed.
8760
8761 If the commit in the engines fail, we still have something logged
8762 to the binary log so we have to report this as a "bad" failure
8763 (failed to commit, but logged something).
8764 */
8765
4/4
✓ Branch 0 taken 7449257 times.
✓ Branch 1 taken 489736 times.
✓ Branch 2 taken 2095774 times.
✓ Branch 3 taken 5353483 times.
7938993 if (stmt_stuff_logged || trx_stuff_logged) {
8766
2/4
✓ Branch 0 taken 2584957 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2585028 times.
✗ Branch 3 not taken.
2585510 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_invoke_before_commit_hook");
8767
6/10
✓ Branch 0 taken 2584845 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2481140 times.
✓ Branch 3 taken 103705 times.
✓ Branch 4 taken 103738 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 103762 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 103804 times.
✗ Branch 9 not taken.
2584989 if (RUN_HOOK(
8768 transaction, before_commit,
8769 (thd, all, thd_get_cache_mngr(thd)->get_trx_cache(),
8770 thd_get_cache_mngr(thd)->get_stmt_cache(),
8771 max<my_off_t>(max_binlog_cache_size, max_binlog_stmt_cache_size),
8772
4/4
✓ Branch 0 taken 2584802 times.
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 2584990 times.
5169835 is_atomic_ddl)) ||
8773
3/4
✓ Branch 0 taken 2584891 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 2584819 times.
2584802 DBUG_EVALUATE_IF("simulate_failure_in_before_commit_hook", true,
8774 false)) {
8775
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 trx_coordinator::rollback_in_engines(thd, all);
8776
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 gtid_state->update_on_rollback(thd);
8777
2/4
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
43 thd_get_cache_mngr(thd)->reset();
8778 // Reset the thread OK status before changing the outcome.
8779
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 15 times.
43 if (thd->get_stmt_da()->is_ok())
8780
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 thd->get_stmt_da()->reset_diagnostics_area();
8781
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 my_error(ER_RUN_HOOK_ERROR, MYF(0), "before_commit");
8782 43 return RESULT_ABORTED;
8783 }
8784 /*
8785 Check whether the transaction should commit or abort given the
8786 plugin feedback.
8787 */
8788 2584990 if (thd->get_transaction()
8789 ->get_rpl_transaction_ctx()
8790
5/6
✓ Branch 0 taken 2584997 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2584189 times.
✓ Branch 3 taken 808 times.
✓ Branch 4 taken 831 times.
✓ Branch 5 taken 2584159 times.
5169172 ->is_transaction_rollback() ||
8791
3/4
✓ Branch 0 taken 2584182 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 2584159 times.
2584189 (DBUG_EVALUATE_IF("simulate_transaction_rollback_request", true,
8792 false))) {
8793
1/2
✓ Branch 0 taken 831 times.
✗ Branch 1 not taken.
831 trx_coordinator::rollback_in_engines(thd, all);
8794
1/2
✓ Branch 0 taken 831 times.
✗ Branch 1 not taken.
831 gtid_state->update_on_rollback(thd);
8795
2/4
✓ Branch 0 taken 831 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 831 times.
✗ Branch 3 not taken.
831 thd_get_cache_mngr(thd)->reset();
8796
2/2
✓ Branch 0 taken 802 times.
✓ Branch 1 taken 29 times.
831 if (thd->get_stmt_da()->is_ok())
8797
1/2
✓ Branch 0 taken 802 times.
✗ Branch 1 not taken.
802 thd->get_stmt_da()->reset_diagnostics_area();
8798
1/2
✓ Branch 0 taken 831 times.
✗ Branch 1 not taken.
831 my_error(ER_TRANSACTION_ROLLBACK_DURING_COMMIT, MYF(0));
8799 831 return RESULT_ABORTED;
8800 }
8801
8802 #ifdef WITH_WSREP
8803 int error;
8804
1/2
✓ Branch 0 taken 2584104 times.
✗ Branch 1 not taken.
2584159 const bool run_wsrep_hooks = wsrep_run_commit_hook(thd, all);
8805 /* Set this flag to trigger execution of ordered commit as part of
8806 thread handler flush stage append flow. */
8807 2584104 thd->run_wsrep_ordered_commit = run_wsrep_hooks;
8808
8809
7/8
✓ Branch 0 taken 46287 times.
✓ Branch 1 taken 2537817 times.
✓ Branch 2 taken 46287 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 46264 times.
✓ Branch 6 taken 23 times.
✓ Branch 7 taken 2584081 times.
2584104 if (run_wsrep_hooks && (error = wsrep_before_commit(thd, all))) {
8810
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 mysql_mutex_lock(&thd->LOCK_wsrep_thd);
8811
3/6
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
23 if (run_wsrep_hooks && wsrep_must_abort(thd)) {
8812 WSREP_DEBUG("BF abort has happened after prepare & certify");
8813 mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
8814 } else {
8815
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
8816 }
8817
8818
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 ha_rollback_low(thd, all);
8819
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 gtid_state->update_on_rollback(thd);
8820
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 thd_get_cache_mngr(thd)->reset();
8821 // Reset the thread OK status before changing the outcome.
8822
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
23 if (!wsrep_must_replay(thd) && thd->get_stmt_da()->is_ok())
8823 thd->get_stmt_da()->reset_diagnostics_area();
8824 /* If wsrep transaction needs to replay, we didn't reset DA data.
8825 It will be used by replayer service. As DA::m_can_overwrite_status
8826 is 'true' here (set in mysql_execute_command() before
8827 trans_commit_stmt()) the following call to my_error() will allow
8828 overwriting the error */
8829
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 my_error(ER_TRANSACTION_ROLLBACK_DURING_COMMIT, MYF(0));
8830 23 return RESULT_ABORTED;
8831 }
8832
8833
1/2
✓ Branch 0 taken 2583036 times.
✗ Branch 1 not taken.
2584081 int rc = ordered_commit(thd, all, skip_commit);
8834
8835
2/2
✓ Branch 0 taken 46166 times.
✓ Branch 1 taken 2536870 times.
2583036 if (run_wsrep_hooks) {
8836
1/2
✓ Branch 0 taken 46260 times.
✗ Branch 1 not taken.
46166 wsrep_after_commit(thd, all);
8837 }
8838
8839 2583130 thd->run_wsrep_ordered_commit = false;
8840 #else
8841 int rc = ordered_commit(thd, all, skip_commit);
8842 #endif /* WITH_WSREP */
8843
8844
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 2583039 times.
2583130 if (rc) return RESULT_INCONSISTENT;
8845
8846
4/6
✓ Branch 0 taken 2582919 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2582916 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
2583039 DBUG_EXECUTE_IF("ensure_binlog_cache_is_reset", {
8847 /* Assert that binlog cache is reset at commit time. */
8848 assert(binlog_cache_is_reset);
8849 binlog_cache_is_reset = false;
8850 };);
8851
8852 /*
8853 Mark the flag m_is_binlogged to true only after we are done
8854 with checking all the error cases.
8855 */
8856
3/4
✓ Branch 0 taken 2582750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 530 times.
✓ Branch 3 taken 2582220 times.
2582919 if (is_loggable_xa_prepare(thd)) {
8857 530 thd->get_transaction()->xid_state()->set_binlogged();
8858 /*
8859 Inform hook listeners that a XA PREPARE did commit, that
8860 is, did log a transaction to the binary log.
8861 */
8862
4/6
✓ Branch 0 taken 530 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 446 times.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
530 (void)RUN_HOOK(transaction, after_commit, (thd, all));
8863 }
8864
2/2
✓ Branch 0 taken 5353403 times.
✓ Branch 1 taken 80 times.
7936228 } else if (!skip_commit) {
8865 /*
8866 We only set engine binlog position in ordered_commit path flush phase
8867 and not all transactions go through them (such as table copy in DDL).
8868 So in cases where a DDL statement implicitly commits earlier transaction
8869 and starting a new one, the new transaction could be "leaking" the
8870 engine binlog pos. In order to avoid that and accidentally overwrite
8871 binlog position with previous location, we reset it here.
8872 */
8873
1/2
✓ Branch 0 taken 5353708 times.
✗ Branch 1 not taken.
5353403 thd->set_trans_pos(nullptr, 0);
8874
3/4
✓ Branch 0 taken 5353530 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 5353516 times.
5353708 if (trx_coordinator::commit_in_engines(thd, all))
8875 14 return RESULT_INCONSISTENT;
8876 }
8877
8878 7936341 return RESULT_SUCCESS;
8879 31171067 }
8880
8881 /**
8882 Flush caches for session.
8883
8884 @note @c set_trans_pos is called with a pointer to the file name
8885 that the binary log currently use and a rotation will change the
8886 contents of the variable.
8887
8888 The position is used when calling the after_flush, after_commit,
8889 and after_rollback hooks, but these have been placed so that they
8890 occur before a rotation is executed.
8891
8892 It is the responsibility of any plugin that use this position to
8893 copy it if they need it after the hook has returned.
8894
8895 The current "global" transaction_counter is stepped and its new value
8896 is assigned to the transaction.
8897 */
8898 2585324 std::pair<int, my_off_t> MYSQL_BIN_LOG::flush_thread_caches(THD *thd) {
8899
1/2
✓ Branch 0 taken 2585324 times.
✗ Branch 1 not taken.
2585324 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
8900 2585324 my_off_t bytes = 0;
8901 2585324 bool wrote_xid = false;
8902
1/2
✓ Branch 0 taken 2585321 times.
✗ Branch 1 not taken.
2585324 int error = cache_mngr->flush(thd, &bytes, &wrote_xid);
8903
3/4
✓ Branch 0 taken 2585317 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2585317 times.
✗ Branch 3 not taken.
2585321 if (!error && bytes > 0) {
8904 /*
8905 Note that set_trans_pos does not copy the file name. See
8906 this function documentation for more info.
8907 */
8908
1/2
✓ Branch 0 taken 2585317 times.
✗ Branch 1 not taken.
2585317 thd->set_trans_pos(log_file_name, m_binlog_file->position());
8909
3/4
✓ Branch 0 taken 2039489 times.
✓ Branch 1 taken 545828 times.
✓ Branch 2 taken 2039489 times.
✗ Branch 3 not taken.
2585317 if (wrote_xid) inc_prep_xids(thd);
8910 }
8911
5/8
✓ Branch 0 taken 2585321 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2585321 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 108 times.
✓ Branch 5 taken 2585213 times.
✓ Branch 6 taken 108 times.
✗ Branch 7 not taken.
2585321 DBUG_PRINT("debug", ("bytes: %llu", bytes));
8912
1/2
✓ Branch 0 taken 2585321 times.
✗ Branch 1 not taken.
5170642 return std::make_pair(error, bytes);
8913 }
8914
8915 2584986 void MYSQL_BIN_LOG::init_thd_variables(THD *thd, bool all, bool skip_commit) {
8916 /*
8917 These values are used while committing a transaction, so clear
8918 everything.
8919
8920 Notes:
8921
8922 - It would be good if we could keep transaction coordinator
8923 log-specific data out of the THD structure, but that is not the
8924 case right now.
8925
8926 - Everything in the transaction structure is reset when calling
8927 ha_commit_low since that calls Transaction_ctx::cleanup.
8928 */
8929 2584986 thd->tx_commit_pending = true;
8930 2584986 thd->commit_error = THD::CE_NONE;
8931 2584986 thd->next_to_commit = nullptr;
8932 2584986 thd->durability_property = HA_IGNORE_DURABILITY;
8933 2584986 thd->get_transaction()->m_flags.real_commit = all;
8934 2585224 thd->get_transaction()->m_flags.xid_written = false;
8935 2585358 thd->get_transaction()->m_flags.commit_low = !skip_commit;
8936 2585352 thd->get_transaction()->m_flags.run_hooks = !skip_commit;
8937 #ifndef NDEBUG
8938 /*
8939 The group commit Leader may have to wait for follower whose transaction
8940 is not ready to be preempted. Initially the status is pessimistic.
8941 Preemption guarding logics is necessary only when !NDEBUG is set.
8942 It won't be required for the dbug-off case as long as the follower won't
8943 execute any thread-specific write access code in this method, which is
8944 the case as of current.
8945 */
8946 2585161 thd->get_transaction()->m_flags.ready_preempt = false;
8947 #endif
8948 2585362 }
8949
8950 2494628 THD *MYSQL_BIN_LOG::fetch_and_process_flush_stage_queue(
8951 const bool check_and_skip_flush_logs) {
8952 /*
8953 Fetch the entire flush queue and empty it, so that the next batch
8954 has a leader. We must do this before invoking ha_flush_logs(...)
8955 for guaranteeing to flush prepared records of transactions before
8956 flushing them to binary log, which is required by crash recovery.
8957 */
8958 2494628 Commit_stage_manager::get_instance().lock_queue(
8959 Commit_stage_manager::BINLOG_FLUSH_STAGE);
8960
8961 THD *first_seen =
8962 2494628 Commit_stage_manager::get_instance().fetch_queue_skip_acquire_lock(
8963 Commit_stage_manager::BINLOG_FLUSH_STAGE);
8964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2494628 times.
2494628 assert(first_seen != nullptr);
8965
8966 THD *commit_order_thd =
8967 2494628 Commit_stage_manager::get_instance().fetch_queue_skip_acquire_lock(
8968 Commit_stage_manager::COMMIT_ORDER_FLUSH_STAGE);
8969
8970 2494628 Commit_stage_manager::get_instance().unlock_queue(
8971 Commit_stage_manager::BINLOG_FLUSH_STAGE);
8972
8973
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2494627 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2494628 if (!check_and_skip_flush_logs ||
8974
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (check_and_skip_flush_logs && commit_order_thd != nullptr)) {
8975 /*
8976 We flush prepared records of transactions to the log of storage
8977 engine (for example, InnoDB redo log) in a group right before
8978 flushing them to binary log.
8979 */
8980 2494627 ha_flush_logs(true);
8981 }
8982
8983 /*
8984 The transactions are flushed to the disk and so threads
8985 executing slave preserve commit order can be unblocked.
8986 */
8987 2494624 Commit_stage_manager::get_instance()
8988 2494624 .process_final_stage_for_ordered_commit_group(commit_order_thd);
8989 2494624 return first_seen;
8990 }
8991
8992 2494627 int MYSQL_BIN_LOG::process_flush_stage_queue(my_off_t *total_bytes_var,
8993 bool *rotate_var,
8994 THD **out_queue_var) {
8995
1/2
✓ Branch 0 taken 2494627 times.
✗ Branch 1 not taken.
2494627 DBUG_TRACE;
8996 #ifndef NDEBUG
8997 // number of flushes per group.
8998 2494627 int no_flushes = 0;
8999 #endif
9000
3/6
✓ Branch 0 taken 2494627 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2494627 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2494627 times.
✗ Branch 5 not taken.
2494627 assert(total_bytes_var && rotate_var && out_queue_var);
9001 2494627 my_off_t total_bytes = 0;
9002 2494627 int flush_error = 1;
9003 mysql_mutex_assert_owner(&LOCK_log);
9004
9005
1/2
✓ Branch 0 taken 2494623 times.
✗ Branch 1 not taken.
2494627 THD *first_seen = fetch_and_process_flush_stage_queue();
9006
4/6
✓ Branch 0 taken 2494623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2494619 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
2494623 DBUG_EXECUTE_IF("crash_after_flush_engine_log", DBUG_SUICIDE(););
9007
2/4
✓ Branch 0 taken 2494619 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2494619 times.
✗ Branch 3 not taken.
2494619 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_write_binlog");
9008
1/2
✓ Branch 0 taken 2494619 times.
✗ Branch 1 not taken.
2494619 assign_automatic_gtids_to_flush_group(first_seen);
9009 /* Flush thread caches to binary log. */
9010
2/2
✓ Branch 0 taken 2585324 times.
✓ Branch 1 taken 2494616 times.
5079940 for (THD *head = first_seen; head; head = head->next_to_commit) {
9011
2/4
✓ Branch 0 taken 2585324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2585324 times.
✗ Branch 3 not taken.
2585324 Thd_backup_and_restore switch_thd(current_thd, head);
9012
1/2
✓ Branch 0 taken 2585321 times.
✗ Branch 1 not taken.
2585324 std::pair<int, my_off_t> result = flush_thread_caches(head);
9013 2585321 total_bytes += result.second;
9014
2/2
✓ Branch 0 taken 2494616 times.
✓ Branch 1 taken 90705 times.
2585321 if (flush_error == 1) flush_error = result.first;
9015 #ifndef NDEBUG
9016 2585321 no_flushes++;
9017 #endif
9018 2585321 }
9019
9020 2494616 *out_queue_var = first_seen;
9021 2494616 *total_bytes_var = total_bytes;
9022
4/4
✓ Branch 0 taken 2494612 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 13609 times.
✓ Branch 3 taken 2481007 times.
4989228 if (total_bytes > 0 &&
9023
2/2
✓ Branch 0 taken 2481004 times.
✓ Branch 1 taken 13608 times.
2494612 (m_binlog_file->get_real_file_size() >= (my_off_t)max_size ||
9024
3/4
✓ Branch 0 taken 2481004 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2481003 times.
2481004 DBUG_EVALUATE_IF("simulate_max_binlog_size", true, false)))
9025 13609 *rotate_var = true;
9026 #ifndef NDEBUG
9027
5/8
✓ Branch 0 taken 2494616 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2494616 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 2494505 times.
✓ Branch 6 taken 111 times.
✗ Branch 7 not taken.
2494616 DBUG_PRINT("info", ("no_flushes:= %d", no_flushes));
9028 2494616 no_flushes = 0;
9029 #endif
9030 2494616 return flush_error;
9031 2494616 }
9032
9033 /**
9034 Commit a sequence of sessions.
9035
9036 This function commit an entire queue of sessions starting with the
9037 session in @c first. If there were an error in the flushing part of
9038 the ordered commit, the error code is passed in and all the threads
9039 are marked accordingly (but not committed).
9040
9041 It will also add the GTIDs of the transactions to gtid_executed.
9042
9043 @see MYSQL_BIN_LOG::ordered_commit
9044
9045 @param thd The "master" thread
9046 @param first First thread in the queue of threads to commit
9047 */
9048
9049 2471053 void MYSQL_BIN_LOG::process_commit_stage_queue(THD *thd, THD *first) {
9050 mysql_mutex_assert_owner(&LOCK_commit);
9051 #ifndef NDEBUG
9052 2471053 thd->get_transaction()->m_flags.ready_preempt =
9053 true; // formality by the leader
9054 #endif
9055
2/2
✓ Branch 0 taken 2584577 times.
✓ Branch 1 taken 2471051 times.
5055628 for (THD *head = first; head; head = head->next_to_commit) {
9056
6/10
✓ Branch 0 taken 2584577 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2584577 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 106 times.
✓ Branch 5 taken 2584471 times.
✓ Branch 6 taken 106 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 106 times.
✗ Branch 9 not taken.
2584577 DBUG_PRINT("debug", ("Thread ID: %u, commit_error: %d, commit_pending: %s",
9057 head->thread_id(), head->commit_error,
9058 YESNO(head->tx_commit_pending)));
9059
2/8
✓ Branch 0 taken 2584577 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2584577 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2584577 DBUG_EXECUTE_IF(
9060 "block_leader_after_delete",
9061 if (thd != head) { DBUG_SET("+d,after_delete_wait"); };);
9062 /*
9063 If flushing failed, set commit_error for the session, skip the
9064 transaction and proceed with the next transaction instead. This
9065 will mark all threads as failed, since the flush failed.
9066
9067 If flush succeeded, attach to the session and commit it in the
9068 engines.
9069 */
9070 #ifndef NDEBUG
9071
2/4
✓ Branch 0 taken 2584577 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2584577 times.
✗ Branch 3 not taken.
2584577 Commit_stage_manager::get_instance().clear_preempt_status(head);
9072 #endif
9073
2/2
✓ Branch 0 taken 2584576 times.
✓ Branch 1 taken 1 times.
2584577 if (head->get_transaction()->sequence_number != SEQ_UNINIT) {
9074
1/2
✓ Branch 0 taken 2584576 times.
✗ Branch 1 not taken.
2584576 mysql_mutex_lock(&LOCK_replica_trans_dep_tracker);
9075
1/2
✓ Branch 0 taken 2584576 times.
✗ Branch 1 not taken.
2584576 m_dependency_tracker.update_max_committed(head);
9076
1/2
✓ Branch 0 taken 2584576 times.
✗ Branch 1 not taken.
2584576 mysql_mutex_unlock(&LOCK_replica_trans_dep_tracker);
9077 }
9078 /*
9079 Flush/Sync error should be ignored and continue
9080 to commit phase. And thd->commit_error cannot be
9081 COMMIT_ERROR at this moment.
9082 */
9083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2584577 times.
2584577 assert(head->commit_error != THD::CE_COMMIT_ERROR);
9084
1/2
✓ Branch 0 taken 2584577 times.
✗ Branch 1 not taken.
2584577 Thd_backup_and_restore switch_thd(thd, head);
9085 2584577 bool all = head->get_transaction()->m_flags.real_commit;
9086
3/4
✓ Branch 0 taken 2582758 times.
✓ Branch 1 taken 1819 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2582758 times.
2584577 assert(!head->get_transaction()->m_flags.commit_low ||
9087 head->get_transaction()->m_flags.ready_preempt);
9088
1/2
✓ Branch 0 taken 2584575 times.
✗ Branch 1 not taken.
2584577 ::finish_transaction_in_engines(head, all, false);
9089
6/10
✓ Branch 0 taken 2584575 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2584575 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 106 times.
✓ Branch 5 taken 2584469 times.
✓ Branch 6 taken 106 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 106 times.
✗ Branch 9 not taken.
2584575 DBUG_PRINT("debug", ("commit_error: %d, commit_pending: %s",
9090 head->commit_error, YESNO(head->tx_commit_pending)));
9091 2584575 }
9092
9093
2/2
✓ Branch 0 taken 2469771 times.
✓ Branch 1 taken 1280 times.
2471051 DEBUG_SYNC(thd, "process_commit_stage_queue_before_handle_gtid");
9094 /*
9095 Handle the GTID of the threads.
9096 gtid_executed table is kept updated even though transactions fail to be
9097 logged. That's required by slave auto positioning.
9098 */
9099 2471051 gtid_state->update_commit_group(first);
9100
9101
2/2
✓ Branch 0 taken 2584563 times.
✓ Branch 1 taken 2471039 times.
5055602 for (THD *head = first; head; head = head->next_to_commit) {
9102
1/2
✓ Branch 0 taken 2584563 times.
✗ Branch 1 not taken.
2584563 Thd_backup_and_restore switch_thd(thd, head);
9103 2584563 auto all = head->get_transaction()->m_flags.real_commit;
9104 // Mark transaction as prepared in TC, if applicable
9105
1/2
✓ Branch 0 taken 2584563 times.
✗ Branch 1 not taken.
2584563 trx_coordinator::set_prepared_in_tc_in_engines(head, all);
9106 /*
9107 Decrement the prepared XID counter after storage engine commit.
9108 We also need decrement the prepared XID when encountering a
9109 flush error or session attach error for avoiding 3-way deadlock
9110 among user thread, rotate thread and dump thread.
9111 */
9112
3/4
✓ Branch 0 taken 2038736 times.
✓ Branch 1 taken 545827 times.
✓ Branch 2 taken 2038736 times.
✗ Branch 3 not taken.
2584563 if (head->get_transaction()->m_flags.xid_written) dec_prep_xids(head);
9113 2584563 }
9114 2471039 }
9115
9116 /**
9117 Process after commit for a sequence of sessions.
9118
9119 @param thd The "master" thread
9120 @param first First thread in the queue of threads to commit
9121 */
9122
9123 2471038 void MYSQL_BIN_LOG::process_after_commit_stage_queue(THD *thd, THD *first) {
9124
2/2
✓ Branch 0 taken 2584562 times.
✓ Branch 1 taken 2471031 times.
5055593 for (THD *head = first; head; head = head->next_to_commit) {
9125
4/4
✓ Branch 0 taken 2582747 times.
✓ Branch 1 taken 1816 times.
✓ Branch 2 taken 2582749 times.
✓ Branch 3 taken 1814 times.
5167309 if (head->get_transaction()->m_flags.run_hooks &&
9126
1/2
✓ Branch 0 taken 2582748 times.
✗ Branch 1 not taken.
2582747 head->commit_error != THD::CE_COMMIT_ERROR) {
9127 /*
9128 TODO: This hook here should probably move outside/below this
9129 if and be the only after_commit invocation left in the
9130 code.
9131 */
9132
1/2
✓ Branch 0 taken 2582749 times.
✗ Branch 1 not taken.
2582749 Thd_backup_and_restore switch_thd(thd, head);
9133 2582749 bool all = head->get_transaction()->m_flags.real_commit;
9134
4/6
✓ Branch 0 taken 2582750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102826 times.
✓ Branch 3 taken 2479924 times.
✓ Branch 4 taken 102818 times.
✗ Branch 5 not taken.
2582749 (void)RUN_HOOK(transaction, after_commit, (head, all));
9135 /*
9136 When after_commit finished for the transaction, clear the run_hooks
9137 flag. This allow other parts of the system to check if after_commit was
9138 called.
9139 */
9140 2582742 head->get_transaction()->m_flags.run_hooks = false;
9141 2582750 }
9142 }
9143 2471031 }
9144
9145 #ifndef NDEBUG
9146 /** Names for the stages. */
9147 static const char *g_stage_name[] = {
9148 "FLUSH",
9149 "SYNC",
9150 "COMMIT",
9151 };
9152 #endif
9153
9154 7566306 bool MYSQL_BIN_LOG::change_stage(THD *thd [[maybe_unused]],
9155 Commit_stage_manager::StageID stage,
9156 THD *queue, mysql_mutex_t *leave_mutex,
9157 mysql_mutex_t *enter_mutex) {
9158
1/2
✓ Branch 0 taken 7566631 times.
✗ Branch 1 not taken.
7566306 DBUG_TRACE;
9159
5/8
✓ Branch 0 taken 7566543 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7566606 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 323 times.
✓ Branch 5 taken 7566283 times.
✓ Branch 6 taken 323 times.
✗ Branch 7 not taken.
7566631 DBUG_PRINT("enter", ("thd: 0x%llx, stage: %s, queue: 0x%llx", (ulonglong)thd,
9160 g_stage_name[stage], (ulonglong)queue));
9161
2/4
✓ Branch 0 taken 7566607 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7566607 times.
✗ Branch 3 not taken.
7566606 assert(0 <= stage && stage < Commit_stage_manager::STAGE_COUNTER);
9162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7566607 times.
7566607 assert(enter_mutex);
9163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7566607 times.
7566607 assert(queue);
9164 /*
9165 enroll_for will release the leave_mutex once the sessions are
9166 queued.
9167 */
9168
4/6
✓ Branch 0 taken 7566325 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7566211 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 113440 times.
✓ Branch 5 taken 7452771 times.
7566607 if (!Commit_stage_manager::get_instance().enroll_for(
9169 stage, queue, leave_mutex, enter_mutex)) {
9170
2/4
✓ Branch 0 taken 113426 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 113404 times.
113440 assert(!thd_get_cache_mngr(thd)->dbug_any_finalized());
9171 113404 return true;
9172 }
9173
9174 7452771 return false;
9175 7566175 }
9176
9177 /**
9178 Flush the I/O cache to file.
9179
9180 Flush the binary log to the binlog file if any byte where written
9181 and signal that the binary log file has been updated if the flush
9182 succeeds.
9183 */
9184
9185 2494612 int MYSQL_BIN_LOG::flush_cache_to_file(my_off_t *end_pos_var) {
9186
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2494610 times.
2494612 if (m_binlog_file->flush()) {
9187 2 THD *thd = current_thd;
9188 2 thd->commit_error = THD::CE_FLUSH_ERROR;
9189 2 return ER_ERROR_ON_WRITE;
9190 }
9191 2494610 *end_pos_var = m_binlog_file->position();
9192 2494610 return 0;
9193 }
9194
9195 /**
9196 Call fsync() to sync the file to disk.
9197 */
9198 4052219 std::pair<bool, bool> MYSQL_BIN_LOG::sync_binlog_file(bool force) {
9199 4052219 bool synced = false;
9200 4052219 unsigned int sync_period = get_sync_period();
9201
8/8
✓ Branch 0 taken 4044154 times.
✓ Branch 1 taken 8065 times.
✓ Branch 2 taken 4003129 times.
✓ Branch 3 taken 41025 times.
✓ Branch 4 taken 2445182 times.
✓ Branch 5 taken 1557947 times.
✓ Branch 6 taken 2453247 times.
✓ Branch 7 taken 1598972 times.
4052219 if (force || (sync_period && ++sync_counter >= sync_period)) {
9202 2453247 sync_counter = 0;
9203
9204 /*
9205 There is a chance that binlog file could be closed by 'RESET MASTER' or
9206 or 'FLUSH LOGS' just after the leader releases LOCK_log and before it
9207 acquires LOCK_sync log. So it should check if m_binlog_file is opened.
9208 */
9209
9/12
✓ Branch 0 taken 2453247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2453243 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2453242 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2453242 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2453242 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 2453243 times.
2453247 if (DBUG_EVALUATE_IF("simulate_error_during_sync_binlog_file", 1,
9210 m_binlog_file->is_open() && m_binlog_file->sync())) {
9211
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 THD *thd = current_thd;
9212 4 thd->commit_error = THD::CE_SYNC_ERROR;
9213
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 return std::make_pair(true, synced);
9214 }
9215 2453243 synced = true;
9216 }
9217
1/2
✓ Branch 0 taken 4052216 times.
✗ Branch 1 not taken.
4052215 return std::make_pair(false, synced);
9218 }
9219
9220 /**
9221 Helper function executed when leaving @c ordered_commit.
9222
9223 This function contain the necessary code for fetching the error
9224 code, doing post-commit checks, and wrapping up the commit if
9225 necessary.
9226
9227 It is typically called when enter_stage indicates that the thread
9228 should bail out, and also when the ultimate leader thread finishes
9229 executing @c ordered_commit.
9230
9231 It is typically used in this manner:
9232 @code
9233 if (enter_stage(thd, Thread_queue::BINLOG_FLUSH_STAGE, thd, &LOCK_log))
9234 return finish_commit(thd);
9235 @endcode
9236
9237 @return Error code if the session commit failed, or zero on
9238 success.
9239 */
9240 2584665 int MYSQL_BIN_LOG::finish_commit(THD *thd) {
9241
1/2
✓ Branch 0 taken 2584973 times.
✗ Branch 1 not taken.
2584665 DBUG_TRACE;
9242
3/4
✓ Branch 0 taken 2583608 times.
✓ Branch 1 taken 1284 times.
✓ Branch 2 taken 2583682 times.
✗ Branch 3 not taken.
2584973 DEBUG_SYNC(thd, "reached_finish_commit");
9243 /*
9244 In some unlikely situations, it can happen that binary
9245 log is closed before the thread flushes it's cache.
9246 In that case, clear the caches before doing commit.
9247 */
9248
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 2584746 times.
2584966 if (unlikely(!is_open())) {
9249
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
9250
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 if (cache_mngr) cache_mngr->reset();
9251 }
9252
9253
2/2
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 2583967 times.
2584761 if (thd->get_transaction()->sequence_number != SEQ_UNINIT) {
9254
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 mysql_mutex_lock(&LOCK_replica_trans_dep_tracker);
9255
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 m_dependency_tracker.update_max_committed(thd);
9256
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 mysql_mutex_unlock(&LOCK_replica_trans_dep_tracker);
9257 }
9258
9259 2584591 auto all = thd->get_transaction()->m_flags.real_commit;
9260 2584545 auto committed_low = thd->get_transaction()->m_flags.commit_low;
9261
9262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2584696 times.
2584696 assert(thd->commit_error != THD::CE_COMMIT_ERROR);
9263
1/2
✓ Branch 0 taken 2584665 times.
✗ Branch 1 not taken.
2584696 ::finish_transaction_in_engines(thd, all, false);
9264
9265 // If the ordered commit didn't updated the GTIDs for this thd yet
9266 // at process_commit_stage_queue (i.e. --binlog-order-commits=0)
9267 // the thd still has the ownership of a GTID and we must handle it.
9268
3/4
✓ Branch 0 taken 2584230 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1316 times.
✓ Branch 3 taken 2582914 times.
2584665 if (!thd->owned_gtid_is_empty()) {
9269
1/2
✓ Branch 0 taken 1316 times.
✗ Branch 1 not taken.
1316 if (thd->commit_error == THD::CE_NONE) {
9270
1/2
✓ Branch 0 taken 1316 times.
✗ Branch 1 not taken.
1316 gtid_state->update_on_commit(thd);
9271 } else
9272 gtid_state->update_on_rollback(thd);
9273 }
9274
9275 // If not yet done, mark transaction as prepared in TC, if applicable and
9276 // unfence the rotation of the binary log
9277
2/2
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 2583588 times.
2584230 if (thd->get_transaction()->m_flags.xid_written) {
9278
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 trx_coordinator::set_prepared_in_tc_in_engines(thd, all);
9279
1/2
✓ Branch 0 taken 568 times.
✗ Branch 1 not taken.
624 dec_prep_xids(thd);
9280 }
9281
9282 // If the transaction was committed successfully, run the after_commit
9283
5/6
✓ Branch 0 taken 1026 times.
✓ Branch 1 taken 2583130 times.
✓ Branch 2 taken 1026 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 624 times.
✓ Branch 5 taken 2583532 times.
2585182 if (committed_low && (thd->commit_error != THD::CE_COMMIT_ERROR) &&
9284
2/2
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 402 times.
1026 thd->get_transaction()->m_flags.run_hooks) {
9285
4/6
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 606 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
624 (void)RUN_HOOK(transaction, after_commit, (thd, all));
9286 624 thd->get_transaction()->m_flags.run_hooks = false;
9287 }
9288
9289
2/10
✓ Branch 0 taken 2584045 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2584045 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
2584156 DBUG_EXECUTE_IF("leaving_finish_commit", {
9290 const char act[] = "now SIGNAL signal_leaving_finish_commit";
9291 assert(!debug_sync_set_action(current_thd, STRING_WITH_LEN(act)));
9292 };);
9293
9294
3/4
✓ Branch 0 taken 2574119 times.
✓ Branch 1 taken 9926 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2574068 times.
2584045 assert(thd->commit_error || !thd->get_transaction()->m_flags.run_hooks);
9295
2/4
✓ Branch 0 taken 2584390 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2584258 times.
2583994 assert(!thd_get_cache_mngr(thd)->dbug_any_finalized());
9296
5/8
✓ Branch 0 taken 2583926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2583849 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 106 times.
✓ Branch 5 taken 2583743 times.
✓ Branch 6 taken 106 times.
✗ Branch 7 not taken.
2584258 DBUG_PRINT("return", ("Thread ID: %u, commit_error: %d", thd->thread_id(),
9297 thd->commit_error));
9298 /*
9299 flush or sync errors are handled by the leader of the group
9300 (using binlog_error_action). Hence treat only COMMIT_ERRORs as errors.
9301 */
9302 2584779 return thd->commit_error == THD::CE_COMMIT_ERROR;
9303 2583849 }
9304
9305 /**
9306 Auxiliary function used in ordered_commit.
9307 */
9308 2471667 static inline int call_after_sync_hook(THD *queue_head) {
9309 2471667 const char *log_file = nullptr;
9310 2471667 my_off_t pos = 0;
9311
9312
3/4
✓ Branch 0 taken 2471667 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2447192 times.
✓ Branch 3 taken 24475 times.
2471667 if (NO_HOOK(binlog_storage)) return 0;
9313
9314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24475 times.
24475 assert(queue_head != nullptr);
9315
2/2
✓ Branch 0 taken 63550 times.
✓ Branch 1 taken 24475 times.
88025 for (THD *thd = queue_head; thd != nullptr; thd = thd->next_to_commit)
9316
1/2
✓ Branch 0 taken 63550 times.
✗ Branch 1 not taken.
63550 if (likely(thd->commit_error == THD::CE_NONE))
9317
1/2
✓ Branch 0 taken 63550 times.
✗ Branch 1 not taken.
63550 thd->get_trans_fixed_pos(&log_file, &pos);
9318
9319
6/8
✓ Branch 0 taken 24475 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24472 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24472 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 24472 times.
48947 if (DBUG_EVALUATE_IF("simulate_after_sync_hook_error", 1, 0) ||
9320
3/6
✓ Branch 0 taken 24472 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24472 times.
✓ Branch 4 taken 24472 times.
✗ Branch 5 not taken.
24472 RUN_HOOK(binlog_storage, after_sync, (queue_head, log_file, pos))) {
9321
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_RUN_AFTER_SYNC_HOOK);
9322 3 return ER_ERROR_ON_WRITE;
9323 }
9324 24472 return 0;
9325 }
9326
9327 /**
9328 Helper function to handle flush or sync stage errors.
9329 If binlog_error_action= ABORT_SERVER, server will be aborted
9330 after reporting the error to the client.
9331 If binlog_error_action= IGNORE_ERROR, binlog will be closed
9332 for the reset of the life time of the server. close() call is protected
9333 with LOCK_log to avoid any parallel operations on binary log.
9334
9335 @param thd Thread object that faced flush/sync error
9336 @param need_lock_log
9337 > Indicates true if LOCk_log is needed before closing
9338 binlog (happens when we are handling sync error)
9339 > Indicates false if LOCK_log is already acquired
9340 by the thread (happens when we are handling flush
9341 error)
9342 @param message Message stating the reason of the failure
9343 */
9344 14 void MYSQL_BIN_LOG::handle_binlog_flush_or_sync_error(THD *thd,
9345 bool need_lock_log,
9346 const char *message) {
9347 14 char errmsg[MYSQL_ERRMSG_SIZE] = {0};
9348
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
14 if (message == nullptr)
9349 24 sprintf(
9350 errmsg,
9351 "An error occurred during %s stage of the commit. "
9352 "'binlog_error_action' is set to '%s'.",
9353
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 thd->commit_error == THD::CE_FLUSH_ERROR ? "flush" : "sync",
9354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 binlog_error_action == ABORT_SERVER ? "ABORT_SERVER" : "IGNORE_ERROR");
9355 else
9356 2 strncpy(errmsg, message, MYSQL_ERRMSG_SIZE - 1);
9357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (binlog_error_action == ABORT_SERVER) {
9358 char err_buff[MYSQL_ERRMSG_SIZE + 25];
9359 sprintf(err_buff, "%s Server is being stopped.", errmsg);
9360 exec_binlog_error_action_abort(err_buff);
9361 } else {
9362
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 DEBUG_SYNC(thd, "before_binlog_closed_due_to_error");
9363
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if (need_lock_log)
9364
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 mysql_mutex_lock(&LOCK_log);
9365 else
9366 mysql_mutex_assert_owner(&LOCK_log);
9367 /*
9368 It can happen that other group leader encountered
9369 error and already closed the binary log. So print
9370 error only if it is in open state. But we should
9371 call close() always just in case if the previous
9372 close did not close index file.
9373 */
9374
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 if (is_open()) {
9375
8/16
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✗ Branch 15 not taken.
13 LogErr(ERROR_LEVEL, ER_TURNING_LOGGING_OFF_FOR_THE_DURATION, errmsg);
9376 }
9377
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT, false /*need_lock_log=false*/,
9378 true /*need_lock_index=true*/);
9379 /*
9380 If there is a write error (flush/sync stage) and if
9381 binlog_error_action=IGNORE_ERROR, clear the error
9382 and allow the commit to happen in storage engine.
9383 */
9384
5/6
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 12 times.
17 if (check_write_error(thd) &&
9385
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
3 DBUG_EVALUATE_IF("simulate_cache_creation_failure", false, true)) {
9386 /* we have DA_ERROR */
9387
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 thd->clear_error(); /* sets thd->get_stmt_da()->status() to DA_EMPTY */
9388 /* For SQLCOM_COMMIT, ROLLBACK, ROLLBACK TO SAVEPOINT, there is already
9389 my_ok() in mysql_execute_command. Doing double my_ok() is not allowed. So
9390 we avoid that here */
9391
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (thd_sql_command(thd) != SQLCOM_COMMIT &&
9392
6/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
3 thd_sql_command(thd) != SQLCOM_ROLLBACK &&
9393
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 thd_sql_command(thd) != SQLCOM_ROLLBACK_TO_SAVEPOINT) {
9394
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_ok(thd); /* sets thd->get_stmt_da()->status() to DA_OK */
9395 }
9396 }
9397
9398
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
14 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
9399
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 DEBUG_SYNC(thd, "after_binlog_closed_due_to_error");
9400 }
9401 14 }
9402
9403 2585087 int MYSQL_BIN_LOG::ordered_commit(THD *thd, bool all, bool skip_commit) {
9404
1/2
✓ Branch 0 taken 2585427 times.
✗ Branch 1 not taken.
2585087 DBUG_TRACE;
9405 2585427 int flush_error = 0, sync_error = 0;
9406 2585427 my_off_t total_bytes = 0;
9407 2585427 bool do_rotate = false;
9408
9409
4/6
✓ Branch 0 taken 2585271 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 2585181 times.
✓ Branch 4 taken 90 times.
✗ Branch 5 not taken.
2585427 DBUG_EXECUTE_IF("crash_commit_before_log", DBUG_SUICIDE(););
9410
9411 #ifdef WITH_WSREP
9412
9/10
✓ Branch 0 taken 2585211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 59175 times.
✓ Branch 3 taken 2526036 times.
✓ Branch 4 taken 59165 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 59109 times.
✓ Branch 7 taken 56 times.
✓ Branch 8 taken 26 times.
✓ Branch 9 taken 59083 times.
2585181 if (WSREP_EMULATE_BINLOG(thd)) {
9413 /*
9414 Skip group commit, just do storage engine commit.
9415 */
9416
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 int rcode = ha_commit_low(thd, all);
9417
9418 /* if there is myisam statement inside innodb transaction, we may
9419 have events in stmt cache
9420 */
9421
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
9422
3/4
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24 times.
26 if (!cache_mngr->stmt_cache.is_binlog_empty()) {
9423
1/40
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
2 WSREP_DEBUG("stmt transaction inside MST, SQL: %s", WSREP_QUERY(thd));
9424
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 cache_mngr->stmt_cache.reset();
9425 }
9426 26 return rcode;
9427 }
9428 #endif /* WITH_WSREP */
9429
9430
1/2
✓ Branch 0 taken 2584962 times.
✗ Branch 1 not taken.
2585155 init_thd_variables(thd, all, skip_commit);
9431
6/10
✓ Branch 0 taken 2585097 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2585223 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 2585112 times.
✓ Branch 6 taken 111 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 111 times.
✗ Branch 9 not taken.
2584962 DBUG_PRINT("enter", ("commit_pending: %s, commit_error: %d, thread_id: %u",
9432 YESNO(thd->tx_commit_pending), thd->commit_error,
9433 thd->thread_id()));
9434
9435
3/4
✓ Branch 0 taken 2583856 times.
✓ Branch 1 taken 1279 times.
✓ Branch 2 taken 2584051 times.
✗ Branch 3 not taken.
2585223 DEBUG_SYNC(thd, "bgc_before_flush_stage");
9436
9437 /*
9438 Stage #0: ensure slave threads commit order as they appear in the slave's
9439 relay log for transactions flushing to binary log.
9440
9441 This will make thread wait until its turn to commit.
9442 Commit_order_manager maintains it own queue and its own order for the
9443 commit. So Stage#0 doesn't maintain separate StageID.
9444 */
9445
1/2
✓ Branch 0 taken 2585096 times.
✗ Branch 1 not taken.
2585330 if (Commit_order_manager::wait_for_its_turn_before_flush_stage(thd) ||
9446
7/8
✓ Branch 0 taken 2570976 times.
✓ Branch 1 taken 14120 times.
✓ Branch 2 taken 2571042 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 187682 times.
✓ Branch 5 taken 2383360 times.
✓ Branch 6 taken 2397551 times.
✓ Branch 7 taken 187679 times.
2772846 ending_trans(thd, all) ||
9447
2/4
✓ Branch 0 taken 187750 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187756 times.
187682 Commit_order_manager::get_rollback_status(thd)) {
9448
3/4
✓ Branch 0 taken 2397554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 2397471 times.
2397551 if (Commit_order_manager::wait(thd)) {
9449 83 return thd->commit_error;
9450 }
9451 }
9452
9453 /*
9454 Stage #1: flushing transactions to binary log
9455
9456 While flushing, we allow new threads to enter and will process
9457 them in due time. Once the queue was empty, we cannot reap
9458 anything more since it is possible that a thread entered and
9459 appointed itself leader for the flush phase.
9460 */
9461
9462
3/4
✓ Branch 0 taken 2585015 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90440 times.
✓ Branch 3 taken 2494575 times.
2585150 if (change_stage(thd, Commit_stage_manager::BINLOG_FLUSH_STAGE, thd, nullptr,
9463 &LOCK_log)) {
9464
3/8
✓ Branch 0 taken 90402 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90422 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 90422 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
90440 DBUG_PRINT("return", ("Thread ID: %u, commit_error: %d", thd->thread_id(),
9465 thd->commit_error));
9466
1/2
✓ Branch 0 taken 90420 times.
✗ Branch 1 not taken.
90422 return finish_commit(thd);
9467 }
9468
9469 #ifdef WITH_WSREP
9470
3/4
✓ Branch 0 taken 2493348 times.
✓ Branch 1 taken 1280 times.
✓ Branch 2 taken 2493348 times.
✗ Branch 3 not taken.
2494575 DEBUG_SYNC(thd, "pxc_in_commit_flush_stage");
9471 #endif /* WITH_WSREP */
9472
9473 2494628 THD *wait_queue = nullptr, *final_queue = nullptr;
9474 2494628 mysql_mutex_t *leave_mutex_before_commit_stage = nullptr;
9475 2494628 my_off_t flush_end_pos = 0;
9476 bool update_binlog_end_pos_after_sync;
9477
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2494627 times.
2494628 if (unlikely(!is_open())) {
9478
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 final_queue = fetch_and_process_flush_stage_queue(true);
9479 1 leave_mutex_before_commit_stage = &LOCK_log;
9480 /*
9481 binary log is closed, flush stage and sync stage should be
9482 ignored. Binlog cache should be cleared, but instead of doing
9483 it here, do that work in 'finish_commit' function so that
9484 leader and followers thread caches will be cleared.
9485 */
9486 1 goto commit_stage;
9487 }
9488
3/4
✓ Branch 0 taken 2493347 times.
✓ Branch 1 taken 1280 times.
✓ Branch 2 taken 2493347 times.
✗ Branch 3 not taken.
2494627 DEBUG_SYNC(thd, "waiting_in_the_middle_of_flush_stage");
9489 flush_error =
9490
1/2
✓ Branch 0 taken 2494616 times.
✗ Branch 1 not taken.
2494627 process_flush_stage_queue(&total_bytes, &do_rotate, &wait_queue);
9491
9492
3/4
✓ Branch 0 taken 2494612 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2494612 times.
✗ Branch 3 not taken.
2494616 if (flush_error == 0 && total_bytes > 0)
9493
1/2
✓ Branch 0 taken 2494612 times.
✗ Branch 1 not taken.
2494612 flush_error = flush_cache_to_file(&flush_end_pos);
9494
4/6
✓ Branch 0 taken 2494616 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2494612 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
2494616 DBUG_EXECUTE_IF("crash_after_flush_binlog", DBUG_SUICIDE(););
9495
9496 2494612 update_binlog_end_pos_after_sync = (get_sync_period() == 1);
9497
9498 /*
9499 If the flush finished successfully, we can call the after_flush
9500 hook. Being invoked here, we have the guarantee that the hook is
9501 executed before the before/after_send_hooks on the dump thread
9502 preventing race conditions among these plug-ins.
9503 */
9504
2/2
✓ Branch 0 taken 2494606 times.
✓ Branch 1 taken 6 times.
2494612 if (flush_error == 0) {
9505
1/2
✓ Branch 0 taken 2494606 times.
✗ Branch 1 not taken.
2494606 const char *file_name_ptr = log_file_name + dirname_length(log_file_name);
9506
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2494606 times.
2494606 assert(flush_end_pos != 0);
9507
5/8
✓ Branch 0 taken 2494606 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2463460 times.
✓ Branch 3 taken 31146 times.
✓ Branch 4 taken 31146 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2494606 times.
2494606 if (RUN_HOOK(binlog_storage, after_flush,
9508 (thd, file_name_ptr, flush_end_pos))) {
9509 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_RUN_AFTER_FLUSH_HOOK);
9510 flush_error = ER_ERROR_ON_WRITE;
9511 }
9512
9513
3/4
✓ Branch 0 taken 42688 times.
✓ Branch 1 taken 2451918 times.
✓ Branch 2 taken 42688 times.
✗ Branch 3 not taken.
2494606 if (!update_binlog_end_pos_after_sync) update_binlog_end_pos();
9514
9515
4/6
✓ Branch 0 taken 2494606 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 2494489 times.
✓ Branch 4 taken 117 times.
✗ Branch 5 not taken.
2494606 DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
9516 }
9517
9518
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2494489 times.
2494495 if (flush_error) {
9519 /*
9520 Handle flush error (if any) after leader finishes it's flush stage.
9521 */
9522
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 handle_binlog_flush_or_sync_error(
9523 thd, false /* need_lock_log */,
9524
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 (thd->commit_error == THD::CE_FLUSH_GNO_EXHAUSTED_ERROR)
9525
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ? ER_THD(thd, ER_GNO_EXHAUSTED)
9526 : nullptr);
9527 }
9528
9529
1/2
✓ Branch 0 taken 2494495 times.
✗ Branch 1 not taken.
2494495 publish_coordinates_for_global_status();
9530
9531
3/4
✓ Branch 0 taken 2493215 times.
✓ Branch 1 taken 1280 times.
✓ Branch 2 taken 2493215 times.
✗ Branch 3 not taken.
2494495 DEBUG_SYNC(thd, "bgc_after_flush_stage_before_sync_stage");
9532
9533 /*
9534 Stage #2: Syncing binary log file to disk
9535 */
9536
9537
3/4
✓ Branch 0 taken 2494478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6942 times.
✓ Branch 3 taken 2487536 times.
2494495 if (change_stage(thd, Commit_stage_manager::SYNC_STAGE, wait_queue, &LOCK_log,
9538 &LOCK_sync)) {
9539
3/8
✓ Branch 0 taken 6937 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6939 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6939 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6942 DBUG_PRINT("return", ("Thread ID: %u, commit_error: %d", thd->thread_id(),
9540 thd->commit_error));
9541
1/2
✓ Branch 0 taken 6936 times.
✗ Branch 1 not taken.
6939 return finish_commit(thd);
9542 }
9543
9544 /*
9545 Shall introduce a delay only if it is going to do sync
9546 in this ongoing SYNC stage. The "+1" used below in the
9547 if condition is to count the ongoing sync stage.
9548 When sync_binlog=0 (where we never do sync in BGC group),
9549 it is considered as a special case and delay will be executed
9550 for every group just like how it is done when sync_binlog= 1.
9551 */
9552
5/6
✓ Branch 0 taken 2487536 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2486110 times.
✓ Branch 3 taken 1426 times.
✓ Branch 4 taken 2486110 times.
✓ Branch 5 taken 1426 times.
2487536 if (!flush_error && (sync_counter + 1 >= get_sync_period()))
9553
2/4
✓ Branch 0 taken 2486110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2486110 times.
✗ Branch 3 not taken.
2486110 Commit_stage_manager::get_instance().wait_count_or_timeout(
9554 opt_binlog_group_commit_sync_no_delay_count,
9555 opt_binlog_group_commit_sync_delay, Commit_stage_manager::SYNC_STAGE);
9556
9557
2/4
✓ Branch 0 taken 2487542 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2487542 times.
✗ Branch 3 not taken.
2487536 final_queue = Commit_stage_manager::get_instance().fetch_queue_acquire_lock(
9558 Commit_stage_manager::SYNC_STAGE);
9559
9560
3/4
✓ Branch 0 taken 2487536 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2487536 times.
✗ Branch 3 not taken.
2487542 if (flush_error == 0 && total_bytes > 0) {
9561
3/4
✓ Branch 0 taken 2486256 times.
✓ Branch 1 taken 1280 times.
✓ Branch 2 taken 2486256 times.
✗ Branch 3 not taken.
2487536 DEBUG_SYNC(thd, "before_sync_binlog_file");
9562
1/2
✓ Branch 0 taken 2487536 times.
✗ Branch 1 not taken.
2487536 std::pair<bool, bool> result = sync_binlog_file(false);
9563 2487536 sync_error = result.first;
9564 }
9565
9566
2/2
✓ Branch 0 taken 2445090 times.
✓ Branch 1 taken 42452 times.
2487542 if (update_binlog_end_pos_after_sync) {
9567 2445090 THD *tmp_thd = final_queue;
9568 2445090 const char *binlog_file = nullptr;
9569 2445090 my_off_t pos = 0;
9570
2/2
✓ Branch 0 taken 48502 times.
✓ Branch 1 taken 2445090 times.
2493592 while (tmp_thd->next_to_commit != nullptr)
9571 48502 tmp_thd = tmp_thd->next_to_commit;
9572
4/4
✓ Branch 0 taken 2445084 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2445080 times.
✓ Branch 3 taken 4 times.
2445090 if (flush_error == 0 && sync_error == 0) {
9573
1/2
✓ Branch 0 taken 2445080 times.
✗ Branch 1 not taken.
2445080 tmp_thd->get_trans_fixed_pos(&binlog_file, &pos);
9574
1/2
✓ Branch 0 taken 2445080 times.
✗ Branch 1 not taken.
2445080 update_binlog_end_pos(binlog_file, pos);
9575 }
9576 }
9577
9578
3/4
✓ Branch 0 taken 2486262 times.
✓ Branch 1 taken 1280 times.
✓ Branch 2 taken 2486262 times.
✗ Branch 3 not taken.
2487542 DEBUG_SYNC(thd, "bgc_after_sync_stage_before_commit_stage");
9579
9580 2487542 leave_mutex_before_commit_stage = &LOCK_sync;
9581 /*
9582 Stage #3: Commit all transactions in order.
9583
9584 This stage is skipped if we do not need to order the commits and
9585 each thread have to execute the handlerton commit instead.
9586
9587 However, since we are keeping the lock from the previous stage, we
9588 need to unlock it if we skip the stage.
9589
9590 We must also step commit_clock before the ha_commit_low() is called
9591 either in ordered fashion (by the leader of this stage) or by the thread
9592 themselves.
9593
9594 We are delaying the handling of sync error until
9595 all locks are released but we should not enter into
9596 commit stage if binlog_error_action is ABORT_SERVER.
9597 */
9598 2487543 commit_stage:
9599 /* Clone needs binlog commit order. */
9600
7/8
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 2486919 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 624 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2486915 times.
✓ Branch 6 taken 2486919 times.
✓ Branch 7 taken 624 times.
2487547 if ((opt_binlog_order_commits || Clone_handler::need_commit_order()) &&
9601
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 (sync_error == 0 || binlog_error_action != ABORT_SERVER)) {
9602
3/4
✓ Branch 0 taken 2486899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15849 times.
✓ Branch 3 taken 2471050 times.
2486919 if (change_stage(thd, Commit_stage_manager::COMMIT_STAGE, final_queue,
9603 leave_mutex_before_commit_stage, &LOCK_commit)) {
9604
3/8
✓ Branch 0 taken 15836 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15831 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15831 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
15849 DBUG_PRINT("return", ("Thread ID: %u, commit_error: %d", thd->thread_id(),
9605 thd->commit_error));
9606
1/2
✓ Branch 0 taken 15837 times.
✗ Branch 1 not taken.
15831 return finish_commit(thd);
9607 }
9608 THD *commit_queue =
9609
2/4
✓ Branch 0 taken 2471053 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2471053 times.
✗ Branch 3 not taken.
2471050 Commit_stage_manager::get_instance().fetch_queue_acquire_lock(
9610 Commit_stage_manager::COMMIT_STAGE);
9611
5/8
✓ Branch 0 taken 2471053 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 186 times.
✓ Branch 3 taken 2470867 times.
✓ Branch 4 taken 186 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 186 times.
✗ Branch 7 not taken.
2471053 DBUG_EXECUTE_IF("semi_sync_3-way_deadlock",
9612 DEBUG_SYNC(thd, "before_process_commit_stage_queue"););
9613
9614
4/4
✓ Branch 0 taken 2471047 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2471043 times.
✓ Branch 3 taken 4 times.
2471053 if (flush_error == 0 && sync_error == 0)
9615
1/2
✓ Branch 0 taken 2471043 times.
✗ Branch 1 not taken.
2471043 sync_error = call_after_sync_hook(commit_queue);
9616
9617 /*
9618 process_commit_stage_queue will call update_on_commit or
9619 update_on_rollback for the GTID owned by each thd in the queue.
9620
9621 This will be done this way to guarantee that GTIDs are added to
9622 gtid_executed in order, to avoid creating unnecessary temporary
9623 gaps and keep gtid_executed as a single interval at all times.
9624
9625 If we allow each thread to call update_on_commit only when they
9626 are at finish_commit, the GTID order cannot be guaranteed and
9627 temporary gaps may appear in gtid_executed. When this happen,
9628 the server would have to add and remove intervals from the
9629 Gtid_set, and adding and removing intervals requires a mutex,
9630 which would reduce performance.
9631 */
9632
1/2
✓ Branch 0 taken 2471039 times.
✗ Branch 1 not taken.
2471053 process_commit_stage_queue(thd, commit_queue);
9633
1/2
✓ Branch 0 taken 2471039 times.
✗ Branch 1 not taken.
2471039 mysql_mutex_unlock(&LOCK_commit);
9634 /*
9635 Process after_commit after LOCK_commit is released for avoiding
9636 3-way deadlock among user thread, rotate thread and dump thread.
9637 */
9638
1/2
✓ Branch 0 taken 2471029 times.
✗ Branch 1 not taken.
2471039 process_after_commit_stage_queue(thd, commit_queue);
9639 2471029 final_queue = commit_queue;
9640 } else {
9641
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 if (leave_mutex_before_commit_stage)
9642
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 mysql_mutex_unlock(leave_mutex_before_commit_stage);
9643
2/4
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 624 times.
✗ Branch 3 not taken.
624 if (flush_error == 0 && sync_error == 0)
9644
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 sync_error = call_after_sync_hook(final_queue);
9645 }
9646
9647 /*
9648 Handle sync error after we release all locks in order to avoid deadlocks
9649 */
9650
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2471646 times.
2471653 if (sync_error)
9651
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 handle_binlog_flush_or_sync_error(thd, true /* need_lock_log */, nullptr);
9652
9653
3/4
✓ Branch 0 taken 2470377 times.
✓ Branch 1 taken 1279 times.
✓ Branch 2 taken 2470382 times.
✗ Branch 3 not taken.
2471653 DEBUG_SYNC(thd, "before_signal_done");
9654 /* Commit done so signal all waiting threads */
9655
2/4
✓ Branch 0 taken 2471657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2471663 times.
✗ Branch 3 not taken.
2471661 Commit_stage_manager::get_instance().signal_done(final_queue);
9656
2/8
✓ Branch 0 taken 2471663 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2471663 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2471663 DBUG_EXECUTE_IF("block_leader_after_delete", {
9657 const char action[] = "now SIGNAL leader_proceed";
9658 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
9659 };);
9660
9661 /*
9662 Finish the commit before executing a rotate, or run the risk of a
9663 deadlock. We don't need the return value here since it is in
9664 thd->commit_error, which is returned below.
9665 */
9666
1/2
✓ Branch 0 taken 2471660 times.
✗ Branch 1 not taken.
2471663 (void)finish_commit(thd);
9667
3/4
✓ Branch 0 taken 2470379 times.
✓ Branch 1 taken 1280 times.
✓ Branch 2 taken 2470381 times.
✗ Branch 3 not taken.
2471660 DEBUG_SYNC(thd, "bgc_after_commit_stage_before_rotation");
9668
9669 /*
9670 If we need to rotate, we do it without commit error.
9671 Otherwise the thd->commit_error will be possibly reset.
9672 */
9673
6/8
✓ Branch 0 taken 2471659 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2471659 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10850 times.
✓ Branch 5 taken 2460809 times.
✓ Branch 6 taken 9697 times.
✓ Branch 7 taken 2461962 times.
2482511 if (DBUG_EVALUATE_IF("force_rotate", 1, 0) ||
9674
2/2
✓ Branch 0 taken 9697 times.
✓ Branch 1 taken 1153 times.
10850 (do_rotate && thd->commit_error == THD::CE_NONE &&
9675
1/2
✓ Branch 0 taken 9697 times.
✗ Branch 1 not taken.
9697 !is_rotating_caused_by_incident)) {
9676 /*
9677 Do not force the rotate as several consecutive groups may
9678 request unnecessary rotations.
9679
9680 NOTE: Run purge_logs wo/ holding LOCK_log because it does not
9681 need the mutex. Otherwise causes various deadlocks.
9682 */
9683
9684
2/4
✓ Branch 0 taken 9695 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9697 times.
✗ Branch 3 not taken.
9697 DEBUG_SYNC(thd, "ready_to_do_rotation");
9685 9696 bool check_purge = false;
9686
1/2
✓ Branch 0 taken 9698 times.
✗ Branch 1 not taken.
9696 mysql_mutex_lock(&LOCK_log);
9687 /*
9688 If rotate fails then depends on binlog_error_action variable
9689 appropriate action will be taken inside rotate call.
9690 */
9691
1/2
✓ Branch 0 taken 9698 times.
✗ Branch 1 not taken.
9698 int error = rotate(false, &check_purge);
9692
1/2
✓ Branch 0 taken 9698 times.
✗ Branch 1 not taken.
9698 mysql_mutex_unlock(&LOCK_log);
9693
9694
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9690 times.
9698 if (error)
9695 8 thd->commit_error = THD::CE_COMMIT_ERROR;
9696
2/2
✓ Branch 0 taken 4961 times.
✓ Branch 1 taken 4729 times.
9690 else if (check_purge)
9697
1/2
✓ Branch 0 taken 4961 times.
✗ Branch 1 not taken.
4961 auto_purge();
9698 }
9699
9700
6/6
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 2471632 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 2471642 times.
2471685 if (binlog_space_limit && binlog_space_total &&
9701
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7 times.
25 binlog_space_total + m_binlog_file->position() > binlog_space_limit)
9702
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
18 purge_logs_by_size(true);
9703
9704 /*
9705 flush or sync errors are handled above (using binlog_error_action).
9706 Hence treat only COMMIT_ERRORs as errors.
9707 */
9708 2471657 return thd->commit_error == THD::CE_COMMIT_ERROR;
9709 2584959 }
9710
9711 /** Copy the current binlog coordinates to the variables used for the
9712 not-in-consistent-snapshot case of SHOW STATUS */
9713 2502501 void MYSQL_BIN_LOG::publish_coordinates_for_global_status(void) const {
9714 mysql_mutex_assert_owner(&LOCK_log);
9715
9716 2502501 mysql_mutex_lock(&LOCK_status);
9717 2502501 strcpy(binlog_global_snapshot_file, log_file_name);
9718 2502501 binlog_global_snapshot_position = m_binlog_file->position();
9719 2502501 mysql_mutex_unlock(&LOCK_status);
9720 2502501 }
9721
9722 325 void MYSQL_BIN_LOG::xlock(void) {
9723 325 mysql_mutex_lock(&LOCK_log);
9724
9725
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
325 assert(!snapshot_lock_acquired);
9726
9727 /*
9728 We must ensure that no writes to binlog and no commits to storage engines
9729 occur after function is called for START TRANSACTION FOR CONSISTENT
9730 SNAPSHOT. With binlog_order_commits=1 (the default) flushing to binlog is
9731 performed under the LOCK_log mutex and commits are done under the
9732 LOCK_commit mutex, both in the stage leader thread. So acquiring those 2
9733 mutexes is sufficient to guarantee atomicity.
9734
9735 With binlog_order_commits=0 commits are performed in parallel by separate
9736 threads with each acquiring a shared lock on LOCK_consistent_snapshot.
9737
9738 binlog_order_commits is a dynamic variable, so we have to keep track what
9739 primitives should be used in xunlock().
9740 */
9741
1/2
✓ Branch 0 taken 325 times.
✗ Branch 1 not taken.
325 if (opt_binlog_order_commits) {
9742 325 mysql_mutex_lock(&LOCK_commit);
9743 } else {
9744 snapshot_lock_acquired = true;
9745 mysql_rwlock_wrlock(&LOCK_consistent_snapshot);
9746 }
9747 325 }
9748
9749 325 void MYSQL_BIN_LOG::xunlock(void) {
9750
1/2
✓ Branch 0 taken 325 times.
✗ Branch 1 not taken.
325 if (!snapshot_lock_acquired) {
9751 325 mysql_mutex_unlock(&LOCK_commit);
9752 } else {
9753 mysql_rwlock_unlock(&LOCK_consistent_snapshot);
9754 snapshot_lock_acquired = false;
9755 }
9756
9757 325 mysql_mutex_unlock(&LOCK_log);
9758 325 }
9759
9760 /*
9761 Copy out the non-directory part of binlog position filename for the
9762 `binlog_snapshot_file' status variable, same way as it is done for
9763 SHOW MASTER STATUS.
9764 */
9765 140255 static void set_binlog_snapshot_file(const char *src) {
9766 mysql_mutex_assert_owner(&LOCK_status);
9767
9768 140255 int dir_len = dirname_length(src);
9769 140255 strmake(binlog_snapshot_file, src + dir_len,
9770 sizeof(binlog_snapshot_file) - 1);
9771 140255 }
9772
9773
9774
9775 11 void MYSQL_BIN_LOG::report_missing_purged_gtids(
9776 const Gtid_set *slave_executed_gtid_set, std::string &errmsg) {
9777
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 DBUG_TRACE;
9778
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 THD *thd = current_thd;
9779
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 Gtid_set gtid_missing(gtid_state->get_lost_gtids()->get_sid_map());
9780
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 gtid_missing.add_gtid_set(gtid_state->get_lost_gtids());
9781
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 gtid_missing.remove_gtid_set(slave_executed_gtid_set);
9782
9783 11 String tmp_uuid;
9784
9785 /* Protects thd->user_vars. */
9786
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 mysql_mutex_lock(&current_thd->LOCK_thd_data);
9787
3/6
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
11 const auto it = current_thd->user_vars.find("replica_uuid");
9788
4/8
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
11 if (it != current_thd->user_vars.end() && it->second->length() > 0) {
9789
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 tmp_uuid.copy(it->second->ptr(), it->second->length(), nullptr);
9790 }
9791
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 mysql_mutex_unlock(&current_thd->LOCK_thd_data);
9792
9793 11 char *missing_gtids = nullptr;
9794 11 char *slave_executed_gtids = nullptr;
9795
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 gtid_missing.to_string(&missing_gtids);
9796
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 slave_executed_gtid_set->to_string(&slave_executed_gtids);
9797
9798 /*
9799 Log the information about the missing purged GTIDs to the error log.
9800 */
9801
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 std::ostringstream log_info;
9802
3/6
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
11 log_info << "The missing transactions are '" << missing_gtids << "'";
9803
9804
9/18
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 11 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 11 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 11 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 11 times.
✗ Branch 17 not taken.
11 LogErr(WARNING_LEVEL, ER_FOUND_MISSING_GTIDS, tmp_uuid.ptr(),
9805 log_info.str().c_str());
9806
9807 /*
9808 Send the information about the slave executed GTIDs and missing
9809 purged GTIDs to slave if the message is less than MYSQL_ERRMSG_SIZE.
9810 */
9811
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 std::ostringstream gtid_info;
9812 gtid_info << "The GTID set sent by the slave is '" << slave_executed_gtids
9813
5/10
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✗ Branch 9 not taken.
11 << "', and the missing transactions are '" << missing_gtids << "'";
9814
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 errmsg.assign(ER_THD(thd, ER_MASTER_HAS_PURGED_REQUIRED_GTIDS));
9815
9816 /* Don't consider the "%s" in the format string. Subtract 2 from the
9817 total length */
9818
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 int total_length = (errmsg.length() - 2 + gtid_info.str().length());
9819
9820
3/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 8 times.
11 DBUG_EXECUTE_IF("simulate_long_missing_gtids",
9821 { total_length = MYSQL_ERRMSG_SIZE + 1; });
9822
9823
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 if (total_length > MYSQL_ERRMSG_SIZE)
9824
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 gtid_info.str(
9825 "The GTID sets and the missing purged transactions are too"
9826 " long to print in this message. For more information,"
9827 " please see the master's error log or the manual for"
9828 " GTID_SUBTRACT");
9829
9830 /* Buffer for formatting the message about the missing GTIDs. */
9831 11 char buff[MYSQL_ERRMSG_SIZE] = {0};
9832
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 snprintf(buff, MYSQL_ERRMSG_SIZE, errmsg.c_str(), gtid_info.str().c_str());
9833
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 errmsg.assign(buff);
9834
9835
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 my_free(missing_gtids);
9836
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 my_free(slave_executed_gtids);
9837 11 }
9838
9839 1 void MYSQL_BIN_LOG::report_missing_gtids(
9840 const Gtid_set *previous_gtid_set, const Gtid_set *slave_executed_gtid_set,
9841 std::string &errmsg) {
9842
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 DBUG_TRACE;
9843
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 THD *thd = current_thd;
9844 1 char *missing_gtids = nullptr;
9845 1 char *slave_executed_gtids = nullptr;
9846
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Gtid_set gtid_missing(slave_executed_gtid_set->get_sid_map());
9847
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 gtid_missing.add_gtid_set(slave_executed_gtid_set);
9848
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 gtid_missing.remove_gtid_set(previous_gtid_set);
9849
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 gtid_missing.to_string(&missing_gtids);
9850
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 slave_executed_gtid_set->to_string(&slave_executed_gtids);
9851
9852 1 String tmp_uuid;
9853
9854 /* Protects thd->user_vars. */
9855
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 mysql_mutex_lock(&current_thd->LOCK_thd_data);
9856
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 const auto it = current_thd->user_vars.find("replica_uuid");
9857
4/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 if (it != current_thd->user_vars.end() && it->second->length() > 0) {
9858
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 tmp_uuid.copy(it->second->ptr(), it->second->length(), nullptr);
9859 }
9860
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 mysql_mutex_unlock(&current_thd->LOCK_thd_data);
9861
9862 /*
9863 Log the information about the missing purged GTIDs to the error log.
9864 */
9865
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::ostringstream log_info;
9866 log_info << "If the binary log files have been deleted from disk,"
9867 " check the consistency of 'GTID_PURGED' variable."
9868 " The missing transactions are '"
9869
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 << missing_gtids << "'";
9870
9/18
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
1 LogErr(WARNING_LEVEL, ER_FOUND_MISSING_GTIDS, tmp_uuid.ptr(),
9871 log_info.str().c_str());
9872 /*
9873 Send the information about the slave executed GTIDs and missing
9874 purged GTIDs to slave if the message is less than MYSQL_ERRMSG_SIZE.
9875 */
9876
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::ostringstream gtid_info;
9877 gtid_info << "The GTID set sent by the slave is '" << slave_executed_gtids
9878
5/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 << "', and the missing transactions are '" << missing_gtids << "'";
9879
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 errmsg.assign(ER_THD(thd, ER_MASTER_HAS_PURGED_REQUIRED_GTIDS));
9880
9881 /* Don't consider the "%s" in the format string. Subtract 2 from the
9882 total length */
9883
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if ((errmsg.length() - 2 + gtid_info.str().length()) > MYSQL_ERRMSG_SIZE)
9884 gtid_info.str(
9885 "The GTID sets and the missing purged transactions are too"
9886 " long to print in this message. For more information,"
9887 " please see the master's error log or the manual for"
9888 " GTID_SUBTRACT");
9889 /* Buffer for formatting the message about the missing GTIDs. */
9890 1 char buff[MYSQL_ERRMSG_SIZE] = {0};
9891
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 snprintf(buff, MYSQL_ERRMSG_SIZE, errmsg.c_str(), gtid_info.str().c_str());
9892
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 errmsg.assign(buff);
9893
9894
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_free(missing_gtids);
9895
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_free(slave_executed_gtids);
9896 1 }
9897
9898 1711967 void MYSQL_BIN_LOG::update_binlog_end_pos(bool need_lock) {
9899
2/2
✓ Branch 0 taken 146858 times.
✓ Branch 1 taken 1565109 times.
1711967 if (need_lock)
9900 146858 lock_binlog_end_pos();
9901 else
9902 mysql_mutex_assert_owner(&LOCK_binlog_end_pos);
9903 1711967 atomic_binlog_end_pos = m_binlog_file->position();
9904 1711967 signal_update();
9905
2/2
✓ Branch 0 taken 146858 times.
✓ Branch 1 taken 1565109 times.
1711967 if (need_lock) unlock_binlog_end_pos();
9906 1711967 }
9907
9908 2445080 inline void MYSQL_BIN_LOG::update_binlog_end_pos(const char *file,
9909 my_off_t pos) {
9910 2445080 lock_binlog_end_pos();
9911
6/6
✓ Branch 0 taken 2445079 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2444953 times.
✓ Branch 3 taken 126 times.
✓ Branch 4 taken 2444953 times.
✓ Branch 5 taken 127 times.
2445080 if (is_active(file) && (pos > atomic_binlog_end_pos))
9912 2444953 atomic_binlog_end_pos = pos;
9913 2445080 signal_update();
9914 2445080 unlock_binlog_end_pos();
9915 2445080 }
9916
9917 2531045 bool THD::is_binlog_cache_empty(bool is_transactional) const {
9918
1/2
✓ Branch 0 taken 2531107 times.
✗ Branch 1 not taken.
2531045 DBUG_TRACE;
9919
9920 // If opt_bin_log==0, it is not safe to call thd_get_cache_mngr
9921 // because binlog_hton has not been completely set up.
9922 #ifdef WITH_WSREP
9923 #else
9924 assert(opt_bin_log);
9925 #endif /* WITH_WSREP */
9926
1/2
✓ Branch 0 taken 2531147 times.
✗ Branch 1 not taken.
2531107 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(this);
9927
9928 // cache_mngr is NULL until we call thd->binlog_setup_trx_data, so
9929 // we assert that this has been done.
9930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2531147 times.
2531147 assert(cache_mngr != nullptr);
9931
9932 binlog_cache_data *cache_data =
9933 2531147 cache_mngr->get_binlog_cache_data(is_transactional);
9934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2531022 times.
2531022 assert(cache_data != nullptr);
9935
9936
1/2
✓ Branch 0 taken 2531099 times.
✗ Branch 1 not taken.
5062156 return cache_data->is_binlog_empty();
9937 2531099 }
9938
9939 /*
9940 These functions are placed in this file since they need access to
9941 binlog_hton, which has internal linkage.
9942 */
9943
9944 7575548 int THD::binlog_setup_trx_data() {
9945
1/2
✓ Branch 0 taken 7576054 times.
✗ Branch 1 not taken.
7575548 DBUG_TRACE;
9946
1/2
✓ Branch 0 taken 7576163 times.
✗ Branch 1 not taken.
7576054 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(this);
9947
9948
2/2
✓ Branch 0 taken 7534141 times.
✓ Branch 1 taken 42022 times.
7576163 if (cache_mngr) /* Already set up */ {
9949 7533744 if (Rpl_thd_context::TX_RPL_STAGE_BEGIN ==
9950
3/4
✓ Branch 0 taken 7533744 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98287 times.
✓ Branch 3 taken 7435457 times.
7534141 rpl_thd_ctx.get_tx_rpl_delegate_stage_status())
9951
1/2
✓ Branch 0 taken 98299 times.
✗ Branch 1 not taken.
98287 rpl_thd_ctx.set_tx_rpl_delegate_stage_status(
9952 Rpl_thd_context::TX_RPL_STAGE_CACHE_CREATED);
9953 7533756 return 0;
9954 }
9955
9956
1/2
✓ Branch 0 taken 42029 times.
✗ Branch 1 not taken.
42022 cache_mngr = (binlog_cache_mngr *)my_malloc(key_memory_binlog_cache_mngr,
9957 sizeof(binlog_cache_mngr),
9958 MYF(MY_ZEROFILL));
9959
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42029 times.
42029 if (!cache_mngr) {
9960 return 1; // Didn't manage to set it up
9961 }
9962
9963 84058 cache_mngr = new (cache_mngr)
9964 binlog_cache_mngr(&binlog_stmt_cache_use, &binlog_stmt_cache_disk_use,
9965
1/2
✓ Branch 0 taken 42029 times.
✗ Branch 1 not taken.
42029 &binlog_cache_use, &binlog_cache_disk_use);
9966
2/4
✓ Branch 0 taken 42029 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42029 times.
42029 if (cache_mngr->init()) {
9967 cache_mngr->~binlog_cache_mngr();
9968 my_free(cache_mngr);
9969 return 1;
9970 }
9971 42029 if (Rpl_thd_context::TX_RPL_STAGE_BEGIN ==
9972
3/4
✓ Branch 0 taken 42029 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5629 times.
✓ Branch 3 taken 36400 times.
42029 rpl_thd_ctx.get_tx_rpl_delegate_stage_status())
9973
1/2
✓ Branch 0 taken 5629 times.
✗ Branch 1 not taken.
5629 rpl_thd_ctx.set_tx_rpl_delegate_stage_status(
9974 Rpl_thd_context::TX_RPL_STAGE_CACHE_CREATED);
9975
9976
5/8
✓ Branch 0 taken 42029 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42029 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 42028 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
42029 DBUG_PRINT("debug", ("Set ha_data slot %d to 0x%llx", binlog_hton->slot,
9977 (ulonglong)cache_mngr));
9978
1/2
✓ Branch 0 taken 42029 times.
✗ Branch 1 not taken.
42029 thd_set_ha_data(this, binlog_hton, cache_mngr);
9979
9980 42029 return 0;
9981 7575785 }
9982
9983 /**
9984
9985 */
9986 4902868 void register_binlog_handler(THD *thd, bool trx) {
9987
1/2
✓ Branch 0 taken 4903040 times.
✗ Branch 1 not taken.
4902868 DBUG_TRACE;
9988 /*
9989 If this is the first call to this function while processing a statement,
9990 the transactional cache does not have a savepoint defined. So, in what
9991 follows:
9992 . an implicit savepoint is defined;
9993 . callbacks are registered;
9994 . binary log is set as read/write.
9995
9996 The savepoint allows for truncating the trx-cache transactional changes
9997 fail. Callbacks are necessary to flush caches upon committing or rolling
9998 back a statement or a transaction. However, notifications do not happen
9999 if the binary log is set as read/write.
10000 */
10001
1/2
✓ Branch 0 taken 4903167 times.
✗ Branch 1 not taken.
4903040 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
10002
2/2
✓ Branch 0 taken 4852202 times.
✓ Branch 1 taken 50706 times.
4903167 if (cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF) {
10003 /*
10004 Set an implicit savepoint in order to be able to truncate a trx-cache.
10005 */
10006 4852202 my_off_t pos = 0;
10007
1/2
✓ Branch 0 taken 4852254 times.
✗ Branch 1 not taken.
4852202 binlog_trans_log_savepos(thd, &pos);
10008
1/2
✓ Branch 0 taken 4852360 times.
✗ Branch 1 not taken.
4852254 cache_mngr->trx_cache.set_prev_position(pos);
10009
10010 /*
10011 Set callbacks in order to be able to call commit or rollback.
10012 */
10013
3/4
✓ Branch 0 taken 3071131 times.
✓ Branch 1 taken 1781229 times.
✓ Branch 2 taken 3071132 times.
✗ Branch 3 not taken.
4852360 if (trx) trans_register_ha(thd, true, binlog_hton, nullptr);
10014
1/2
✓ Branch 0 taken 4852381 times.
✗ Branch 1 not taken.
4852361 trans_register_ha(thd, false, binlog_hton, nullptr);
10015
10016 /*
10017 Set the binary log as read/write otherwise callbacks are not called.
10018 */
10019
2/4
✓ Branch 0 taken 4852325 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4852337 times.
✗ Branch 3 not taken.
4852381 thd->get_ha_data(binlog_hton->slot)->ha_info[0].set_trx_read_write();
10020 }
10021 4903043 }
10022
10023 /**
10024 Function to start a statement and optionally a transaction for the
10025 binary log.
10026
10027 This function does three things:
10028 - Starts a transaction if not in autocommit mode or if a BEGIN
10029 statement has been seen.
10030
10031 - Start a statement transaction to allow us to truncate the cache.
10032
10033 - Save the current binlog position so that we can roll back the
10034 statement by truncating the cache.
10035
10036 We only update the saved position if the old one was undefined,
10037 the reason is that there are some cases (e.g., for CREATE-SELECT)
10038 where the position is saved twice (e.g., both in
10039 Query_result_create::prepare() and THD::binlog_write_table_map()), but
10040 we should use the first. This means that calls to this function
10041 can be used to start the statement before the first table map
10042 event, to include some extra events.
10043
10044 Note however that IMMEDIATE_LOGGING implies that the statement is
10045 written without BEGIN/COMMIT.
10046
10047 @param thd Thread variable
10048 @param start_event The first event requested to be written into the
10049 binary log
10050 */
10051 4994172 static int binlog_start_trans_and_stmt(THD *thd, Log_event *start_event) {
10052
1/2
✓ Branch 0 taken 4994328 times.
✗ Branch 1 not taken.
4994172 DBUG_TRACE;
10053
10054 /*
10055 Initialize the cache manager if this was not done yet.
10056 */
10057
2/4
✓ Branch 0 taken 4994237 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4994237 times.
4994328 if (thd->binlog_setup_trx_data()) return 1;
10058
10059 /*
10060 Retrieve the appropriated cache.
10061 */
10062 4994237 bool is_transactional = start_event->is_using_trans_cache();
10063
1/2
✓ Branch 0 taken 4994405 times.
✗ Branch 1 not taken.
4994196 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
10064 binlog_cache_data *cache_data =
10065 4994405 cache_mngr->get_binlog_cache_data(is_transactional);
10066
10067 /*
10068 If the event is requesting immediate logging, there is no need to go
10069 further down and set savepoint and register callbacks.
10070 */
10071
2/2
✓ Branch 0 taken 91302 times.
✓ Branch 1 taken 4903047 times.
4994279 if (start_event->is_using_immediate_logging()) return 0;
10072
10073
1/2
✓ Branch 0 taken 4903103 times.
✗ Branch 1 not taken.
4903047 register_binlog_handler(thd, thd->in_multi_stmt_transaction_mode());
10074
10075 /* Transactional DDL is logged traditionally without BEGIN. */
10076
2/2
✓ Branch 0 taken 317991 times.
✓ Branch 1 taken 4584872 times.
4903103 if (is_atomic_ddl_event(start_event)) return 0;
10077
10078 /*
10079 If the cache is empty log "BEGIN" at the beginning of every transaction.
10080 Here, a transaction is either a BEGIN..COMMIT/ROLLBACK block or a single
10081 statement in autocommit mode.
10082 */
10083
3/4
✓ Branch 0 taken 4585063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2136763 times.
✓ Branch 3 taken 2448300 times.
4584872 if (cache_data->is_binlog_empty()) {
10084 static const char begin[] = "BEGIN";
10085 2136763 const char *query = nullptr;
10086 char buf[XID::ser_buf_size];
10087 char xa_start[sizeof("XA START") + 1 + sizeof(buf)];
10088 2136763 XID_STATE *xs = thd->get_transaction()->xid_state();
10089 2136755 int qlen = sizeof(begin) - 1;
10090
10091
6/6
✓ Branch 0 taken 1738010 times.
✓ Branch 1 taken 398745 times.
✓ Branch 2 taken 664 times.
✓ Branch 3 taken 1737349 times.
✓ Branch 4 taken 664 times.
✓ Branch 5 taken 2136094 times.
2136755 if (is_transactional && xs->has_state(XID_STATE::XA_ACTIVE)) {
10092 /*
10093 XA-prepare logging case.
10094 */
10095 664 qlen = sprintf(xa_start, "XA START %s", xs->get_xid()->serialize(buf));
10096 664 query = xa_start;
10097 } else {
10098 /*
10099 Regular transaction case.
10100 */
10101 2136094 query = begin;
10102 }
10103
10104 Query_log_event qinfo(thd, query, qlen, is_transactional, false, true, 0,
10105
1/2
✓ Branch 0 taken 2136608 times.
✗ Branch 1 not taken.
2136758 true);
10106
2/4
✓ Branch 0 taken 2136762 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2136762 times.
2136608 if (cache_data->write_event(&qinfo)) return 1;
10107
1/2
✓ Branch 0 taken 2136448 times.
✗ Branch 1 not taken.
2136762 }
10108
10109 4584748 return 0;
10110 4994007 }
10111
10112 /**
10113 This function writes a table map to the binary log.
10114 Note that in order to keep the signature uniform with related methods,
10115 we use a redundant parameter to indicate whether a transactional table
10116 was changed or not.
10117 Sometimes it will write a Rows_query_log_event into binary log before
10118 the table map too.
10119
10120 @param table a pointer to the table.
10121 @param is_transactional @c true indicates a transactional table,
10122 otherwise @c false a non-transactional.
10123 @param binlog_rows_query @c true indicates a Rows_query log event
10124 will be binlogged before table map,
10125 otherwise @c false indicates it will not
10126 be binlogged.
10127 @return
10128 nonzero if an error pops up when writing the table map event
10129 or the Rows_query log event.
10130 */
10131 4247015 int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
10132 bool binlog_rows_query) {
10133 int error;
10134
1/2
✓ Branch 0 taken 4247161 times.
✗ Branch 1 not taken.
4247015 DBUG_TRACE;
10135
5/8
✓ Branch 0 taken 4247109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4247126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 4247103 times.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
4247161 DBUG_PRINT("enter", ("table: %p (%s: #%llu)", table, table->s->table_name.str,
10136 table->s->table_map_id.id()));
10137
10138 /* Pre-conditions */
10139 #ifdef WITH_WSREP
10140
11/12
✓ Branch 0 taken 4247104 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 108242 times.
✓ Branch 3 taken 4138862 times.
✓ Branch 4 taken 108240 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 108238 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 108173 times.
✓ Branch 9 taken 65 times.
✓ Branch 10 taken 4247073 times.
✗ Branch 11 not taken.
4247126 assert(is_current_stmt_binlog_format_row() &&
10141 (WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open()));
10142 #else
10143 assert(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
10144 #endif /* WITH_WSREP */
10145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4247039 times.
4247138 assert(table->s->table_map_id.is_valid());
10146
10147 4247039 Table_map_log_event the_event(this, table, table->s->table_map_id,
10148
1/2
✓ Branch 0 taken 4247029 times.
✗ Branch 1 not taken.
4247039 is_transactional);
10149
10150
1/2
✓ Branch 0 taken 4247149 times.
✗ Branch 1 not taken.
4247029 binlog_start_trans_and_stmt(this, &the_event);
10151
10152
1/2
✓ Branch 0 taken 4247164 times.
✗ Branch 1 not taken.
4247149 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(this);
10153
10154 binlog_cache_data *cache_data =
10155 4247164 cache_mngr->get_binlog_cache_data(is_transactional);
10156
10157
7/8
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 4246983 times.
✓ Branch 2 taken 77 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 75 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 75 times.
✓ Branch 7 taken 4246985 times.
4247158 if (binlog_rows_query && this->query().str) {
10158 /* Write the Rows_query_log_event into binlog before the table map */
10159 150 Rows_query_log_event rows_query_ev(this, this->query().str,
10160
3/6
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
75 this->query().length);
10161
2/4
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
75 if ((error = cache_data->write_event(&rows_query_ev))) return error;
10162
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 }
10163
10164
2/4
✓ Branch 0 taken 4247066 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4247066 times.
4247060 if ((error = cache_data->write_event(&the_event))) return error;
10165
10166 4247066 binlog_table_maps++;
10167 4247066 return 0;
10168 4247066 }
10169
10170 /**
10171 This function retrieves a pending row event from a cache which is
10172 specified through the parameter @c is_transactional. Respectively, when it
10173 is @c true, the pending event is returned from the transactional cache.
10174 Otherwise from the non-transactional cache.
10175
10176 @param is_transactional @c true indicates a transactional cache,
10177 otherwise @c false a non-transactional.
10178 @return
10179 The row event if any.
10180 */
10181 89193148 Rows_log_event *THD::binlog_get_pending_rows_event(
10182 bool is_transactional) const {
10183 89193148 Rows_log_event *rows = nullptr;
10184 89193148 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(this);
10185
10186 /*
10187 This is less than ideal, but here's the story: If there is no cache_mngr,
10188 prepare_pending_rows_event() has never been called (since the cache_mngr
10189 is set up there). In that case, we just return NULL.
10190 */
10191
2/2
✓ Branch 0 taken 68282456 times.
✓ Branch 1 taken 20913335 times.
89195791 if (cache_mngr) {
10192 binlog_cache_data *cache_data =
10193 68282456 cache_mngr->get_binlog_cache_data(is_transactional);
10194
10195 68281033 rows = cache_data->pending();
10196 }
10197 89195569 return (rows);
10198 }
10199
10200 /**
10201 @param db_param db name c-string to be inserted into alphabetically sorted
10202 THD::binlog_accessed_db_names list.
10203
10204 Note, that space for both the data and the node
10205 struct are allocated in THD::main_mem_root.
10206 The list lasts for the top-level query time and is reset
10207 in @c THD::cleanup_after_query().
10208 */
10209 1509647 void THD::add_to_binlog_accessed_dbs(const char *db_param) {
10210 char *after_db;
10211 /*
10212 binlog_accessed_db_names list is to maintain the database
10213 names which are referenced in a given command.
10214 Prior to bug 17806014 fix, 'main_mem_root' memory root used
10215 to store this list. The 'main_mem_root' scope is till the end
10216 of the query. Hence it caused increasing memory consumption
10217 problem in big procedures like the ones mentioned below.
10218 Eg: CALL p1() where p1 is having 1,00,000 create and drop tables.
10219 'main_mem_root' is freed only at the end of the command CALL p1()'s
10220 execution. But binlog_accessed_db_names list scope is only till the
10221 individual statements specified the procedure(create/drop statements).
10222 Hence the memory allocated in 'main_mem_root' was left uncleared
10223 until the p1's completion, even though it is not required after
10224 completion of individual statements.
10225
10226 Instead of using 'main_mem_root' whose scope is complete query execution,
10227 now the memroot is changed to use 'thd->mem_root' whose scope is until the
10228 individual statement in CALL p1(). 'thd->mem_root' is set to
10229 'execute_mem_root' in the context of procedure and it's scope is till the
10230 individual statement in CALL p1() and thd->memroot is equal to
10231 'main_mem_root' in the context of a normal 'top level query'.
10232
10233 Eg: a) create table t1(i int); => If this function is called while
10234 processing this statement, thd->memroot is equal to &main_mem_root
10235 which will be freed immediately after executing this statement.
10236 b) CALL p1() -> p1 contains create table t1(i int); => If this function
10237 is called while processing create table statement which is inside
10238 a stored procedure, then thd->memroot is equal to 'execute_mem_root'
10239 which will be freed immediately after executing this statement.
10240 In both a and b case, thd->memroot will be freed immediately and will not
10241 increase memory consumption.
10242
10243 A special case(stored functions/triggers):
10244 Consider the following example:
10245 create function f1(i int) returns int
10246 begin
10247 insert into db1.t1 values (1);
10248 insert into db2.t1 values (2);
10249 end;
10250 When we are processing SELECT f1(), the list should contain db1, db2 names.
10251 Since thd->mem_root contains 'execute_mem_root' in the context of
10252 stored function, the mem root will be freed after adding db1 in
10253 the list and when we are processing the second statement and when we try
10254 to add 'db2' in the db1's list, it will lead to crash as db1's memory
10255 is already freed. To handle this special case, if in_sub_stmt is set
10256 (which is true in case of stored functions/triggers), we use &main_mem_root,
10257 if not set we will use thd->memroot which changes it's value to
10258 'execute_mem_root' or '&main_mem_root' depends on the context.
10259 */
10260
2/2
✓ Branch 0 taken 359 times.
✓ Branch 1 taken 1509288 times.
1509647 MEM_ROOT *db_mem_root = in_sub_stmt ? &main_mem_root : mem_root;
10261
10262
2/2
✓ Branch 0 taken 1189967 times.
✓ Branch 1 taken 319680 times.
1509647 if (!binlog_accessed_db_names)
10263
1/2
✓ Branch 0 taken 1189867 times.
✗ Branch 1 not taken.
1189967 binlog_accessed_db_names = new (db_mem_root) List<char>;
10264
10265
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 1509076 times.
1509460 if (binlog_accessed_db_names->elements > MAX_DBS_IN_EVENT_MTS) {
10266 384 push_warning_printf(
10267 this, Sql_condition::SL_WARNING, ER_MTS_UPDATED_DBS_GREATER_MAX,
10268 ER_THD(this, ER_MTS_UPDATED_DBS_GREATER_MAX), MAX_DBS_IN_EVENT_MTS);
10269 384 return;
10270 }
10271
10272 1509076 after_db = strdup_root(db_mem_root, db_param);
10273
10274 /*
10275 sorted insertion is implemented with first rearranging data
10276 (pointer to char*) of the links and final appending of the least
10277 ordered data to create a new link in the list.
10278 */
10279
2/2
✓ Branch 0 taken 319505 times.
✓ Branch 1 taken 1189916 times.
1509421 if (binlog_accessed_db_names->elements != 0) {
10280
1/2
✓ Branch 0 taken 319505 times.
✗ Branch 1 not taken.
319505 List_iterator<char> it(*get_binlog_accessed_db_names());
10281
10282
2/2
✓ Branch 0 taken 391406 times.
✓ Branch 1 taken 15286 times.
406692 while (it++) {
10283 391406 char *swap = nullptr;
10284 391406 char **ref_cur_db = it.ref();
10285 391406 int cmp = strcmp(after_db, *ref_cur_db);
10286
10287
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 391406 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
391406 assert(!swap || cmp < 0);
10288
10289
2/2
✓ Branch 0 taken 304219 times.
✓ Branch 1 taken 87187 times.
391406 if (cmp == 0) {
10290 304219 after_db = nullptr; /* dup to ignore */
10291 304219 break;
10292
3/4
✓ Branch 0 taken 87187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18773 times.
✓ Branch 3 taken 68414 times.
87187 } else if (swap || cmp > 0) {
10293 18773 swap = *ref_cur_db;
10294 18773 *ref_cur_db = after_db;
10295 18773 after_db = swap;
10296 }
10297 }
10298 }
10299
2/2
✓ Branch 0 taken 1204932 times.
✓ Branch 1 taken 304489 times.
1509421 if (after_db) binlog_accessed_db_names->push_back(after_db, db_mem_root);
10300 }
10301
10302 /*
10303 Tells if two (or more) tables have auto_increment columns and we want to
10304 lock those tables with a write lock.
10305
10306 SYNOPSIS
10307 has_two_write_locked_tables_with_auto_increment
10308 tables Table list
10309
10310 NOTES:
10311 Call this function only when you have established the list of all tables
10312 which you'll want to update (including stored functions, triggers, views
10313 inside your statement).
10314 */
10315
10316 928524 static bool has_write_table_with_auto_increment(TABLE_LIST *tables) {
10317
2/2
✓ Branch 0 taken 2060589 times.
✓ Branch 1 taken 815054 times.
2875643 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10318 /* we must do preliminary checks as table->table may be NULL */
10319
6/6
✓ Branch 0 taken 1831810 times.
✓ Branch 1 taken 229206 times.
✓ Branch 2 taken 771863 times.
✓ Branch 3 taken 1059947 times.
✓ Branch 4 taken 113898 times.
✓ Branch 5 taken 1947119 times.
2832453 if (!table->is_placeholder() && table->table->found_next_number_field &&
10320
2/2
✓ Branch 0 taken 113898 times.
✓ Branch 1 taken 657966 times.
771863 (table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE))
10321 113898 return true;
10322 }
10323
10324 815054 return false;
10325 }
10326
10327 /*
10328 checks if we have select tables in the table list and write tables
10329 with auto-increment column.
10330
10331 SYNOPSIS
10332 has_two_write_locked_tables_with_auto_increment_and_query_block
10333 tables Table list
10334
10335 RETURN VALUES
10336
10337 -true if the table list has at least one table with auto-increment column
10338 and at least one table to select from.
10339 -false otherwise
10340 */
10341
10342 919096 static bool has_write_table_with_auto_increment_and_query_block(
10343 TABLE_LIST *tables) {
10344 919096 bool has_query_block = false;
10345 919096 bool has_auto_increment_tables = has_write_table_with_auto_increment(tables);
10346
2/2
✓ Branch 0 taken 1350793 times.
✓ Branch 1 taken 446766 times.
1797559 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10347
4/4
✓ Branch 0 taken 1122659 times.
✓ Branch 1 taken 228213 times.
✓ Branch 2 taken 472816 times.
✓ Branch 3 taken 878013 times.
2473409 if (!table->is_placeholder() &&
10348
2/2
✓ Branch 0 taken 472817 times.
✓ Branch 1 taken 649799 times.
1122659 (table->lock_descriptor().type <= TL_READ_NO_INSERT)) {
10349 472816 has_query_block = true;
10350 472816 break;
10351 }
10352 }
10353
4/4
✓ Branch 0 taken 472818 times.
✓ Branch 1 taken 446764 times.
✓ Branch 2 taken 418 times.
✓ Branch 3 taken 472400 times.
919582 return (has_query_block && has_auto_increment_tables);
10354 }
10355
10356 /*
10357 Tells if there is a table whose auto_increment column is a part
10358 of a compound primary key while is not the first column in
10359 the table definition.
10360
10361 @param tables Table list
10362
10363 @return true if the table exists, fais if does not.
10364 */
10365
10366 919071 static bool has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables) {
10367
2/2
✓ Branch 0 taken 2050312 times.
✓ Branch 1 taken 919564 times.
2969876 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10368 /* we must do preliminary checks as table->table may be NULL */
10369
2/2
✓ Branch 0 taken 772132 times.
✓ Branch 1 taken 1049541 times.
3871985 if (!table->is_placeholder() && table->table->found_next_number_field &&
10370
6/6
✓ Branch 0 taken 1821673 times.
✓ Branch 1 taken 229151 times.
✓ Branch 2 taken 113920 times.
✓ Branch 3 taken 658205 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 2050805 times.
3986417 (table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE) &&
10371
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 113908 times.
113920 table->table->s->next_number_keypart != 0)
10372 12 return true;
10373 }
10374
10375 919564 return false;
10376 }
10377
10378 /**
10379 Checks if a table has a column with a non-deterministic DEFAULT expression.
10380 */
10381 10856 static bool has_nondeterministic_default(const TABLE *table) {
10382 21712 return std::any_of(
10383 10856 table->field, table->field + table->s->fields, [](const Field *field) {
10384
4/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 19632 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 14 times.
19686 return field->m_default_val_expr != nullptr &&
10385 19686 field->m_default_val_expr->get_stmt_unsafe_flags() != 0;
10386 10856 });
10387 }
10388
10389 /**
10390 Checks if a TABLE_LIST contains a table that has been opened for writing, and
10391 that has a column with a non-deterministic DEFAULT expression.
10392 */
10393 9434 static bool has_write_table_with_nondeterministic_default(
10394 const TABLE_LIST *tables) {
10395
2/2
✓ Branch 0 taken 11338 times.
✓ Branch 1 taken 9421 times.
20759 for (const TABLE_LIST *table = tables; table != nullptr;
10396 11325 table = table->next_global) {
10397 /* we must do preliminary checks as table->table may be NULL */
10398 11338 if (!table->is_placeholder() &&
10399
6/6
✓ Branch 0 taken 11272 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 10856 times.
✓ Branch 3 taken 416 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 11325 times.
22194 table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE &&
10400
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10843 times.
10856 has_nondeterministic_default(table->table))
10401 13 return true;
10402 }
10403 9421 return false;
10404 }
10405
10406 /**
10407 Checks if we have reads from ACL tables in table list.
10408
10409 @param thd Current thread
10410 @param tl_list TABLE_LIST used by current command.
10411
10412 @returns true, if we statement is unsafe, otherwise false.
10413 */
10414 919025 static bool has_acl_table_read(THD *thd, const TABLE_LIST *tl_list) {
10415
2/2
✓ Branch 0 taken 2050265 times.
✓ Branch 1 taken 918663 times.
2968928 for (const TABLE_LIST *tl = tl_list; tl != nullptr; tl = tl->next_global) {
10416
4/4
✓ Branch 0 taken 404537 times.
✓ Branch 1 taken 1646226 times.
✓ Branch 2 taken 868 times.
✓ Branch 3 taken 2049903 times.
2454810 if (is_acl_table_in_non_LTM(tl, thd->locked_tables_mode) &&
10417
2/2
✓ Branch 0 taken 403661 times.
✓ Branch 1 taken 876 times.
404537 (tl->lock_descriptor().type == TL_READ_DEFAULT ||
10418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 403677 times.
403661 tl->lock_descriptor().type == TL_READ_HIGH_PRIORITY))
10419 868 return true;
10420 }
10421 918663 return false;
10422 }
10423
10424 /*
10425 Function to check whether the table in query uses a fulltext parser
10426 plugin or not.
10427
10428 @param s - table share pointer.
10429
10430 @retval true - The table uses fulltext parser plugin.
10431 @retval false - Otherwise.
10432 */
10433 5062919 static bool inline fulltext_unsafe_set(TABLE_SHARE *s) {
10434
2/2
✓ Branch 0 taken 4242669 times.
✓ Branch 1 taken 5061655 times.
9304324 for (unsigned int i = 0; i < s->keys; i++) {
10435
5/6
✓ Branch 0 taken 1264 times.
✓ Branch 1 taken 4241405 times.
✓ Branch 2 taken 1264 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1264 times.
✓ Branch 5 taken 4241405 times.
4242669 if ((s->key_info[i].flags & HA_USES_PARSER) && s->keys_in_use.is_set(i))
10436 1264 return true;
10437 }
10438 5061655 return false;
10439 }
10440 #ifndef NDEBUG
10441 156 const char *get_locked_tables_mode_name(
10442 enum_locked_tables_mode locked_tables_mode) {
10443
2/5
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
156 switch (locked_tables_mode) {
10444 151 case LTM_NONE:
10445 151 return "LTM_NONE";
10446 case LTM_LOCK_TABLES:
10447 return "LTM_LOCK_TABLES";
10448 5 case LTM_PRELOCKED:
10449 5 return "LTM_PRELOCKED";
10450 case LTM_PRELOCKED_UNDER_LOCK_TABLES:
10451 return "LTM_PRELOCKED_UNDER_LOCK_TABLES";
10452 default:
10453 return "Unknown table lock mode";
10454 }
10455 }
10456 #endif
10457
10458 /**
10459 Decide on logging format to use for the statement and issue errors
10460 or warnings as needed. The decision depends on the following
10461 parameters:
10462
10463 - The logging mode, i.e., the value of binlog_format. Can be
10464 statement, mixed, or row.
10465
10466 - The type of statement. There are three types of statements:
10467 "normal" safe statements; unsafe statements; and row injections.
10468 An unsafe statement is one that, if logged in statement format,
10469 might produce different results when replayed on the slave (e.g.,
10470 queries with a LIMIT clause). A row injection is either a BINLOG
10471 statement, or a row event executed by the slave's SQL thread.
10472
10473 - The capabilities of tables modified by the statement. The
10474 *capabilities vector* for a table is a set of flags associated
10475 with the table. Currently, it only includes two flags: *row
10476 capability flag* and *statement capability flag*.
10477
10478 The row capability flag is set if and only if the engine can
10479 handle row-based logging. The statement capability flag is set if
10480 and only if the table can handle statement-based logging.
10481
10482 Decision table for logging format
10483 ---------------------------------
10484
10485 The following table summarizes how the format and generated
10486 warning/error depends on the tables' capabilities, the statement
10487 type, and the current binlog_format.
10488
10489 Row capable N NNNNNNNNN YYYYYYYYY YYYYYYYYY
10490 Statement capable N YYYYYYYYY NNNNNNNNN YYYYYYYYY
10491
10492 Statement type * SSSUUUIII SSSUUUIII SSSUUUIII
10493
10494 binlog_format * SMRSMRSMR SMRSMRSMR SMRSMRSMR
10495
10496 Logged format - SS-S----- -RR-RR-RR SRRSRR-RR
10497 Warning/Error 1 --2732444 5--5--6-- ---7--6--
10498
10499 Legend
10500 ------
10501
10502 Row capable: N - Some table not row-capable, Y - All tables row-capable
10503 Stmt capable: N - Some table not stmt-capable, Y - All tables stmt-capable
10504 Statement type: (S)afe, (U)nsafe, or Row (I)njection
10505 binlog_format: (S)TATEMENT, (M)IXED, or (R)OW
10506 Logged format: (S)tatement or (R)ow
10507 Warning/Error: Warnings and error messages are as follows:
10508
10509 1. Error: Cannot execute statement: binlogging impossible since both
10510 row-incapable engines and statement-incapable engines are
10511 involved.
10512
10513 2. Error: Cannot execute statement: binlogging impossible since
10514 BINLOG_FORMAT = ROW and at least one table uses a storage engine
10515 limited to statement-logging.
10516
10517 3. Error: Cannot execute statement: binlogging of unsafe statement
10518 is impossible when storage engine is limited to statement-logging
10519 and BINLOG_FORMAT = MIXED.
10520
10521 4. Error: Cannot execute row injection: binlogging impossible since
10522 at least one table uses a storage engine limited to
10523 statement-logging.
10524
10525 5. Error: Cannot execute statement: binlogging impossible since
10526 BINLOG_FORMAT = STATEMENT and at least one table uses a storage
10527 engine limited to row-logging.
10528
10529 6. Error: Cannot execute row injection: binlogging impossible since
10530 BINLOG_FORMAT = STATEMENT.
10531
10532 7. Warning: Unsafe statement binlogged in statement format since
10533 BINLOG_FORMAT = STATEMENT.
10534
10535 In addition, we can produce the following error (not depending on
10536 the variables of the decision diagram):
10537
10538 8. Error: Cannot execute statement: binlogging impossible since more
10539 than one engine is involved and at least one engine is
10540 self-logging.
10541
10542 9. Error: Do not allow users to modify a gtid_executed table
10543 explicitly by a XA transaction.
10544
10545 For each error case above, the statement is prevented from being
10546 logged, we report an error, and roll back the statement. For
10547 warnings, we set the thd->binlog_flags variable: the warning will be
10548 printed only if the statement is successfully logged.
10549
10550 @see THD::binlog_query
10551
10552 @param[in] tables Tables involved in the query
10553
10554 @retval 0 No error; statement can be logged.
10555 @retval -1 One of the error conditions above applies (1, 2, 4, 5, 6 or 9).
10556 */
10557
10558 30388334 int THD::decide_logging_format(TABLE_LIST *tables) {
10559
1/2
✓ Branch 0 taken 30390510 times.
✗ Branch 1 not taken.
30388334 DBUG_TRACE;
10560
6/10
✓ Branch 0 taken 30389471 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30390193 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 163 times.
✓ Branch 5 taken 30390030 times.
✓ Branch 6 taken 163 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 163 times.
✗ Branch 9 not taken.
30390510 DBUG_PRINT("info", ("query: %s", query().str));
10561
5/8
✓ Branch 0 taken 30389831 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30390002 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 163 times.
✓ Branch 5 taken 30389839 times.
✓ Branch 6 taken 163 times.
✗ Branch 7 not taken.
30390193 DBUG_PRINT("info", ("variables.binlog_format: %lu", variables.binlog_format));
10562
6/10
✓ Branch 0 taken 30389463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30389980 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 163 times.
✓ Branch 5 taken 30389817 times.
✓ Branch 6 taken 163 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 163 times.
✗ Branch 9 not taken.
30390002 DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
10563 lex->get_stmt_unsafe_flags()));
10564
10565 #if defined(ENABLED_DEBUG_SYNC)
10566
3/4
✓ Branch 0 taken 30389418 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30348556 times.
✓ Branch 3 taken 40862 times.
30389980 if (!is_attachable_ro_transaction_active())
10567
3/4
✓ Branch 0 taken 28329582 times.
✓ Branch 1 taken 2018494 times.
✓ Branch 2 taken 28331103 times.
✗ Branch 3 not taken.
30348556 DEBUG_SYNC(this, "begin_decide_logging_format");
10568 #endif
10569
10570 30390459 reset_binlog_local_stmt_filter();
10571
10572 /*
10573 We should not decide logging format if the binlog is closed or
10574 binlogging is off, or if the statement is filtered out from the
10575 binlog by filtering rules.
10576 */
10577 #ifdef WITH_WSREP
10578
12/14
✓ Branch 0 taken 30390213 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3160071 times.
✓ Branch 3 taken 27230142 times.
✓ Branch 4 taken 512059 times.
✓ Branch 5 taken 2648012 times.
✓ Branch 6 taken 464758 times.
✓ Branch 7 taken 47301 times.
✓ Branch 8 taken 464709 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 314642 times.
✓ Branch 11 taken 150067 times.
✓ Branch 12 taken 858 times.
✓ Branch 13 taken 30389289 times.
30704838 if (WSREP(this) && wsrep_thd_is_local(this) &&
10579
2/2
✓ Branch 0 taken 858 times.
✓ Branch 1 taken 313784 times.
314642 variables.wsrep_trx_fragment_size > 0) {
10580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 858 times.
858 if (!is_current_stmt_binlog_format_row()) {
10581 my_message(ER_NOT_SUPPORTED_YET,
10582 "Streaming replication not supported with "
10583 "binlog_format=STATEMENT",
10584 MYF(0));
10585 return -1;
10586 }
10587 }
10588
10589
8/8
✓ Branch 0 taken 512014 times.
✓ Branch 1 taken 2648003 times.
✓ Branch 2 taken 464724 times.
✓ Branch 3 taken 47290 times.
✓ Branch 4 taken 461198 times.
✓ Branch 5 taken 3526 times.
✓ Branch 6 taken 25746629 times.
✓ Branch 7 taken 4639887 times.
33546533 if ((WSREP_EMULATE_BINLOG_NNULL(this) ||
10590
6/6
✓ Branch 0 taken 3160017 times.
✓ Branch 1 taken 27230130 times.
✓ Branch 2 taken 23474082 times.
✓ Branch 3 taken 2272547 times.
✓ Branch 4 taken 23475431 times.
✓ Branch 5 taken 6914629 times.
87410780 (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG))) &&
10591
2/2
✓ Branch 0 taken 2058204 times.
✓ Branch 1 taken 21419404 times.
23477608 !(variables.binlog_format == BINLOG_FORMAT_STMT &&
10592
3/4
✓ Branch 0 taken 2058222 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2056101 times.
✓ Branch 3 taken 2121 times.
2058204 !binlog_filter->db_ok(m_db.str))) {
10593 #else
10594 if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
10595 !(variables.binlog_format == BINLOG_FORMAT_STMT &&
10596 !binlog_filter->db_ok(m_db.str))) {
10597 #endif /* WITH_WSREP */
10598 /*
10599 Compute one bit field with the union of all the engine
10600 capabilities, and one with the intersection of all the engine
10601 capabilities.
10602 */
10603 23475431 handler::Table_flags flags_write_some_set = 0;
10604 23475431 handler::Table_flags flags_access_some_set = 0;
10605 23475431 handler::Table_flags flags_write_all_set =
10606 HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
10607
10608 /*
10609 If different types of engines are about to be updated.
10610 For example: Innodb and Falcon; Innodb and MyIsam.
10611 */
10612 23475431 bool multi_write_engine = false;
10613 /*
10614 If different types of engines are about to be accessed
10615 and any of them is about to be updated. For example:
10616 Innodb and Falcon; Innodb and MyIsam.
10617 */
10618 23475431 bool multi_access_engine = false;
10619 /*
10620 Track if statement creates or drops a temporary table
10621 and log in ROW if it does.
10622 */
10623 23475431 bool is_create_drop_temp_table = false;
10624 /*
10625 Identifies if a table is changed.
10626 */
10627 23475431 bool is_write = false;
10628 /*
10629 A pointer to a previous table that was changed.
10630 */
10631 23475431 TABLE *prev_write_table = nullptr;
10632 /*
10633 A pointer to a previous table that was accessed.
10634 */
10635 23475431 TABLE *prev_access_table = nullptr;
10636 /*
10637 True if at least one table is transactional.
10638 */
10639 23475431 bool write_to_some_transactional_table = false;
10640 /*
10641 True if at least one table is non-transactional.
10642 */
10643 23475431 bool write_to_some_non_transactional_table = false;
10644 /*
10645 True if all non-transactional tables that has been updated
10646 are temporary.
10647 */
10648 23475431 bool write_all_non_transactional_are_tmp_tables = true;
10649 /**
10650 The number of tables used in the current statement,
10651 that should be replicated.
10652 */
10653 23475431 uint replicated_tables_count = 0;
10654 /**
10655 The number of tables written to in the current statement,
10656 that should not be replicated.
10657 A table should not be replicated when it is considered
10658 'local' to a MySQL instance.
10659 Currently, these tables are:
10660 - mysql.slow_log
10661 - mysql.general_log
10662 - mysql.slave_relay_log_info
10663 - mysql.slave_master_info
10664 - mysql.slave_worker_info
10665 - performance_schema.*
10666 - TODO: information_schema.*
10667 In practice, from this list, only performance_schema.* tables
10668 are written to by user queries.
10669 */
10670 23475431 uint non_replicated_tables_count = 0;
10671 /**
10672 Indicate whether we already reported a warning
10673 on modifying gtid_executed table.
10674 */
10675 23475431 int warned_gtid_executed_table = 0;
10676 #ifndef NDEBUG
10677 {
10678
6/10
✓ Branch 0 taken 23475239 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23475288 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 156 times.
✓ Branch 5 taken 23475132 times.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
✗ Branch 9 not taken.
23475431 DBUG_PRINT("debug", ("prelocked_mode: %s",
10679 get_locked_tables_mode_name(locked_tables_mode)));
10680 }
10681 #endif
10682
10683
4/4
✓ Branch 0 taken 3960513 times.
✓ Branch 1 taken 19514775 times.
✓ Branch 2 taken 919501 times.
✓ Branch 3 taken 3041012 times.
23475288 if (variables.binlog_format != BINLOG_FORMAT_ROW && tables) {
10684 /*
10685 DML statements that modify a table with an auto_increment column based
10686 on rows selected from a table are unsafe as the order in which the rows
10687 are fetched from the select tables cannot be determined and may differ
10688 on master and slave.
10689 */
10690
2/2
✓ Branch 0 taken 418 times.
✓ Branch 1 taken 919193 times.
919501 if (has_write_table_with_auto_increment_and_query_block(tables))
10691
1/2
✓ Branch 0 taken 418 times.
✗ Branch 1 not taken.
418 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
10692
10693
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 919571 times.
919611 if (has_write_table_auto_increment_not_first_in_pk(tables))
10694
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST);
10695
10696 /*
10697 A query that modifies autoinc column in sub-statement can make the
10698 master and slave inconsistent.
10699 We can solve these problems in mixed mode by switching to binlogging
10700 if at least one updated table is used by sub-statement
10701 */
10702
6/6
✓ Branch 0 taken 9434 times.
✓ Branch 1 taken 910148 times.
✓ Branch 2 taken 325 times.
✓ Branch 3 taken 9100 times.
✓ Branch 4 taken 325 times.
✓ Branch 5 taken 919248 times.
929008 if (lex->requires_prelocking() &&
10703 9434 has_write_table_with_auto_increment(lex->first_not_own_table()))
10704
1/2
✓ Branch 0 taken 325 times.
✗ Branch 1 not taken.
325 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
10705
10706 /*
10707 A query that modifies a table with a non-deterministic column default
10708 expression in a substatement, can make the master and the slave
10709 inconsistent. Switch to row logging in mixed mode, and raise a warning
10710 in statement mode.
10711 */
10712
4/4
✓ Branch 0 taken 9434 times.
✓ Branch 1 taken 910075 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 919393 times.
928904 if (lex->requires_prelocking() &&
10713
3/4
✓ Branch 0 taken 9331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 9318 times.
9434 has_write_table_with_nondeterministic_default(
10714 9434 lex->first_not_own_table()))
10715
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 lex->set_stmt_unsafe(
10716 LEX::BINLOG_STMT_UNSAFE_DEFAULT_EXPRESSION_IN_SUBSTATEMENT);
10717
10718 /*
10719 A DML or DDL statement is unsafe if it reads a ACL table while
10720 modifying the table, because SE skips acquiring row locks.
10721 Therefore rows seen by DML or DDL may not have same effect on slave.
10722
10723 We skip checking the same under lock tables mode, because we do
10724 not skip row locks on ACL table in this mode.
10725 */
10726
3/4
✓ Branch 0 taken 919553 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 868 times.
✓ Branch 3 taken 918685 times.
919406 if (has_acl_table_read(this, tables)) {
10727
1/2
✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
868 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_ACL_TABLE_READ_IN_DML_DDL);
10728 }
10729 }
10730
10731 /*
10732 Get the capabilities vector for all involved storage engines and
10733 mask out the flags for the binary log.
10734 */
10735
2/2
✓ Branch 0 taken 10917874 times.
✓ Branch 1 taken 23475947 times.
34393821 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10736
2/2
✓ Branch 0 taken 1056460 times.
✓ Branch 1 taken 9862338 times.
10917874 if (table->is_placeholder()) {
10737 /*
10738 Detect if this is a CREATE TEMPORARY or DROP of a
10739 temporary table. This will be used later in determining whether to
10740 log in ROW or STMT if MIXED replication is being used.
10741 */
10742
6/6
✓ Branch 0 taken 1056457 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 745085 times.
✓ Branch 3 taken 311372 times.
✓ Branch 4 taken 8209 times.
✓ Branch 5 taken 1048251 times.
1801545 if (!is_create_drop_temp_table && !table->table &&
10743
2/2
✓ Branch 0 taken 130388 times.
✓ Branch 1 taken 614697 times.
745085 ((lex->sql_command == SQLCOM_CREATE_TABLE &&
10744
2/2
✓ Branch 0 taken 122179 times.
✓ Branch 1 taken 8209 times.
130388 (lex->create_info->options & HA_LEX_CREATE_TMP_TABLE)) ||
10745
2/2
✓ Branch 0 taken 599821 times.
✓ Branch 1 taken 137055 times.
736876 ((lex->sql_command == SQLCOM_DROP_TABLE ||
10746
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 599820 times.
599821 lex->sql_command == SQLCOM_TRUNCATE) &&
10747
2/4
✓ Branch 0 taken 137056 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 137056 times.
137056 find_temporary_table(this, table)))) {
10748 8209 is_create_drop_temp_table = true;
10749 }
10750 1056460 continue;
10751 }
10752 9862338 handler::Table_flags const flags = table->table->file->ha_table_flags();
10753
10754
5/8
✓ Branch 0 taken 9861752 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9862044 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 382 times.
✓ Branch 5 taken 9861662 times.
✓ Branch 6 taken 382 times.
✗ Branch 7 not taken.
9861299 DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
10755 table->table_name, flags));
10756
10757
2/2
✓ Branch 0 taken 886550 times.
✓ Branch 1 taken 8975494 times.
9862044 if (table->table->no_replicate) {
10758
1/2
✓ Branch 0 taken 886550 times.
✗ Branch 1 not taken.
886550 if (!warned_gtid_executed_table) {
10759 warned_gtid_executed_table =
10760
1/2
✓ Branch 0 taken 886550 times.
✗ Branch 1 not taken.
886550 gtid_state->warn_or_err_on_modify_gtid_table(this, table);
10761 /*
10762 Do not allow users to modify the gtid_executed table
10763 explicitly by a XA transaction.
10764 */
10765
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 886547 times.
886550 if (warned_gtid_executed_table == 2) return -1;
10766 }
10767 /*
10768 The statement uses a table that is not replicated.
10769 The following properties about the table:
10770 - persistent / transient
10771 - transactional / non transactional
10772 - temporary / permanent
10773 - read or write
10774 - multiple engines involved because of this table
10775 are not relevant, as this table is completely ignored.
10776 Because the statement uses a non replicated table,
10777 using STATEMENT format in the binlog is impossible.
10778 Either this statement will be discarded entirely,
10779 or it will be logged (possibly partially) in ROW format.
10780 */
10781
1/2
✓ Branch 0 taken 886547 times.
✗ Branch 1 not taken.
886547 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
10782
10783
2/2
✓ Branch 0 taken 7925 times.
✓ Branch 1 taken 878622 times.
886547 if (table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE) {
10784 7925 non_replicated_tables_count++;
10785 7925 continue;
10786 }
10787 }
10788
10789 9854116 replicated_tables_count++;
10790
10791 9854116 bool trans = table->table->file->has_transactions();
10792
10793
2/2
✓ Branch 0 taken 5061088 times.
✓ Branch 1 taken 4793231 times.
9854329 if (table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE) {
10794 5061088 write_to_some_transactional_table =
10795
4/4
✓ Branch 0 taken 4734014 times.
✓ Branch 1 taken 327074 times.
✓ Branch 2 taken 4316467 times.
✓ Branch 3 taken 417547 times.
5061088 write_to_some_transactional_table || trans;
10796
10797 5061088 write_to_some_non_transactional_table =
10798
4/4
✓ Branch 0 taken 5049650 times.
✓ Branch 1 taken 11438 times.
✓ Branch 2 taken 413040 times.
✓ Branch 3 taken 4636610 times.
5061088 write_to_some_non_transactional_table || !trans;
10799
10800
2/2
✓ Branch 0 taken 337866 times.
✓ Branch 1 taken 4723222 times.
5061088 if (prev_write_table &&
10801
2/2
✓ Branch 0 taken 7771 times.
✓ Branch 1 taken 330095 times.
337866 prev_write_table->file->ht != table->table->file->ht)
10802 7771 multi_write_engine = true;
10803
10804
2/2
✓ Branch 0 taken 97133 times.
✓ Branch 1 taken 4963955 times.
5061088 if (table->table->s->tmp_table)
10805
3/4
✓ Branch 0 taken 95669 times.
✓ Branch 1 taken 1464 times.
✓ Branch 2 taken 97136 times.
✗ Branch 3 not taken.
97133 lex->set_stmt_accessed_table(
10806 trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE
10807 : LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE);
10808 else
10809
3/4
✓ Branch 0 taken 4546127 times.
✓ Branch 1 taken 417828 times.
✓ Branch 2 taken 4964296 times.
✗ Branch 3 not taken.
4963955 lex->set_stmt_accessed_table(trans
10810 ? LEX::STMT_WRITES_TRANS_TABLE
10811 : LEX::STMT_WRITES_NON_TRANS_TABLE);
10812
10813 /*
10814 Non-transactional updates are allowed when row binlog format is
10815 used and all non-transactional tables are temporary.
10816 Binlog format is checked on THD::is_dml_gtid_compatible() method.
10817 */
10818
2/2
✓ Branch 0 taken 418974 times.
✓ Branch 1 taken 4642458 times.
5061432 if (!trans)
10819 418974 write_all_non_transactional_are_tmp_tables =
10820
2/2
✓ Branch 0 taken 413307 times.
✓ Branch 1 taken 5667 times.
832281 write_all_non_transactional_are_tmp_tables &&
10821
2/2
✓ Branch 0 taken 1461 times.
✓ Branch 1 taken 411846 times.
413307 table->table->s->tmp_table;
10822
10823 5061432 flags_write_all_set &= flags;
10824 5061432 flags_write_some_set |= flags;
10825 5061432 is_write = true;
10826
10827 5061432 prev_write_table = table->table;
10828
10829 /*
10830 It should be marked unsafe if a table which uses a fulltext parser
10831 plugin is modified. See also bug#48183.
10832 */
10833
1/2
✓ Branch 0 taken 5060257 times.
✗ Branch 1 not taken.
5061432 if (!lex->is_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_FULLTEXT_PLUGIN)) {
10834
2/2
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 5060647 times.
5060257 if (fulltext_unsafe_set(table->table->s))
10835
1/2
✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
169 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_FULLTEXT_PLUGIN);
10836 }
10837 /*
10838 INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique
10839 keys can be unsafe. Check for it if the flag is already not marked for
10840 the given statement.
10841 */
10842 5060800 if (!lex->is_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS) &&
10843
5/6
✓ Branch 0 taken 5061105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4129524 times.
✓ Branch 3 taken 931581 times.
✓ Branch 4 taken 73234 times.
✓ Branch 5 taken 4987830 times.
9190588 lex->sql_command == SQLCOM_INSERT &&
10844
2/2
✓ Branch 0 taken 73234 times.
✓ Branch 1 taken 4056290 times.
4129524 lex->duplicates == DUP_UPDATE) {
10845 73234 uint keys = table->table->s->keys, i = 0, unique_keys = 0;
10846 73234 for (KEY *keyinfo = table->table->s->key_info;
10847
4/4
✓ Branch 0 taken 75934 times.
✓ Branch 1 taken 73225 times.
✓ Branch 2 taken 75925 times.
✓ Branch 3 taken 9 times.
149159 i < keys && unique_keys <= 1; i++, keyinfo++) {
10848
2/2
✓ Branch 0 taken 73355 times.
✓ Branch 1 taken 2570 times.
75925 if (keyinfo->flags & HA_NOSAME) unique_keys++;
10849 }
10850
2/2
✓ Branch 0 taken 160 times.
✓ Branch 1 taken 73074 times.
73234 if (unique_keys > 1)
10851
1/2
✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
160 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS);
10852 }
10853 }
10854
2/2
✓ Branch 0 taken 2781 times.
✓ Branch 1 taken 9850981 times.
9854295 if (lex->get_using_match()) {
10855
2/2
✓ Branch 0 taken 1095 times.
✓ Branch 1 taken 1686 times.
2781 if (fulltext_unsafe_set(table->table->s))
10856
1/2
✓ Branch 0 taken 1095 times.
✗ Branch 1 not taken.
1095 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_FULLTEXT_PLUGIN);
10857 }
10858
10859 9853762 flags_access_some_set |= flags;
10860
10861
4/4
✓ Branch 0 taken 28387 times.
✓ Branch 1 taken 9825375 times.
✓ Branch 2 taken 9844374 times.
✓ Branch 3 taken 9388 times.
9882149 if (lex->sql_command != SQLCOM_CREATE_TABLE ||
10862
1/2
✓ Branch 0 taken 28387 times.
✗ Branch 1 not taken.
28387 (lex->sql_command == SQLCOM_CREATE_TABLE &&
10863
2/2
✓ Branch 0 taken 26138 times.
✓ Branch 1 taken 2249 times.
28387 ((lex->create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
10864
2/2
✓ Branch 0 taken 16625 times.
✓ Branch 1 taken 9513 times.
26138 (table->lock_descriptor().type < TL_WRITE_ALLOW_WRITE)))) {
10865
2/2
✓ Branch 0 taken 111808 times.
✓ Branch 1 taken 9732566 times.
9844374 if (table->table->s->tmp_table)
10866
3/4
✓ Branch 0 taken 106839 times.
✓ Branch 1 taken 4969 times.
✓ Branch 2 taken 111810 times.
✗ Branch 3 not taken.
111808 lex->set_stmt_accessed_table(
10867 trans ? LEX::STMT_READS_TEMP_TRANS_TABLE
10868 : LEX::STMT_READS_TEMP_NON_TRANS_TABLE);
10869 else
10870
3/4
✓ Branch 0 taken 8616737 times.
✓ Branch 1 taken 1115829 times.
✓ Branch 2 taken 9733569 times.
✗ Branch 3 not taken.
9732566 lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TRANS_TABLE
10871 : LEX::STMT_READS_NON_TRANS_TABLE);
10872 }
10873
10874
2/2
✓ Branch 0 taken 2751229 times.
✓ Branch 1 taken 7103538 times.
9854767 if (prev_access_table &&
10875
2/2
✓ Branch 0 taken 22103 times.
✓ Branch 1 taken 2729126 times.
2751229 prev_access_table->file->ht != table->table->file->ht)
10876 22103 multi_access_engine = true;
10877
10878 9854767 prev_access_table = table->table;
10879 }
10880
5/6
✓ Branch 0 taken 4723585 times.
✓ Branch 1 taken 18752362 times.
✓ Branch 2 taken 406815 times.
✓ Branch 3 taken 4316770 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 406815 times.
23475947 assert(!is_write || write_to_some_transactional_table ||
10881 write_to_some_non_transactional_table);
10882 /*
10883 write_all_non_transactional_are_tmp_tables may be true if any
10884 non-transactional table was not updated, so we fix its value here.
10885 */
10886 23475947 write_all_non_transactional_are_tmp_tables =
10887
4/4
✓ Branch 0 taken 23063092 times.
✓ Branch 1 taken 412855 times.
✓ Branch 2 taken 1289 times.
✓ Branch 3 taken 23061803 times.
23475947 write_all_non_transactional_are_tmp_tables &&
10888 write_to_some_non_transactional_table;
10889
10890
5/8
✓ Branch 0 taken 23475125 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23475205 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 23475045 times.
✓ Branch 6 taken 160 times.
✗ Branch 7 not taken.
23475947 DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
10891
5/8
✓ Branch 0 taken 23475122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23475130 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 23474970 times.
✓ Branch 6 taken 160 times.
✗ Branch 7 not taken.
23475205 DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
10892
5/8
✓ Branch 0 taken 23475053 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23475141 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 23474981 times.
✓ Branch 6 taken 160 times.
✗ Branch 7 not taken.
23475130 DBUG_PRINT("info",
10893 ("flags_access_some_set: 0x%llx", flags_access_some_set));
10894
5/8
✓ Branch 0 taken 23474991 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23475124 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 23474964 times.
✓ Branch 6 taken 160 times.
✗ Branch 7 not taken.
23475141 DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
10895
5/8
✓ Branch 0 taken 23474936 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23475113 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 23474953 times.
✓ Branch 6 taken 29 times.
✗ Branch 7 not taken.
23475124 DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
10896
10897 23474982 int error = 0;
10898 int unsafe_flags;
10899
10900 /*
10901 With transactional data dictionary, CREATE TABLE runs as one statement
10902 in a multi-statement transaction internally. Revert this for the
10903 purposes of determining mixed statement safety.
10904 */
10905
4/4
✓ Branch 0 taken 23321396 times.
✓ Branch 1 taken 153586 times.
✓ Branch 2 taken 7907342 times.
✓ Branch 3 taken 15413945 times.
46796269 const bool multi_stmt_trans = lex->sql_command != SQLCOM_CREATE_TABLE &&
10906 23321396 in_multi_stmt_transaction_mode();
10907
1/2
✓ Branch 0 taken 23475225 times.
✗ Branch 1 not taken.
23474873 bool trans_table = trans_has_updated_trans_table(this);
10908 23475225 bool binlog_direct = variables.binlog_direct_non_trans_update;
10909
10910
2/2
✓ Branch 0 taken 2931 times.
✓ Branch 1 taken 23473051 times.
23475982 if (lex->is_mixed_stmt_unsafe(multi_stmt_trans, binlog_direct, trans_table,
10911
1/2
✓ Branch 0 taken 23475982 times.
✗ Branch 1 not taken.
23475225 tx_isolation))
10912
1/2
✓ Branch 0 taken 2931 times.
✗ Branch 1 not taken.
2931 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
10913
8/8
✓ Branch 0 taken 7904696 times.
✓ Branch 1 taken 15568355 times.
✓ Branch 2 taken 6991554 times.
✓ Branch 3 taken 913142 times.
✓ Branch 4 taken 6954155 times.
✓ Branch 5 taken 37399 times.
✓ Branch 6 taken 1346 times.
✓ Branch 7 taken 23471705 times.
30427206 else if (multi_stmt_trans && trans_table && !binlog_direct &&
10914
3/4
✓ Branch 0 taken 6954155 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1346 times.
✓ Branch 3 taken 6952809 times.
6954155 lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE))
10915
1/2
✓ Branch 0 taken 1346 times.
✗ Branch 1 not taken.
1346 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
10916
10917 /*
10918 If more than one engine is involved in the statement and at
10919 least one is doing it's own logging (is *self-logging*), the
10920 statement cannot be logged atomically, so we generate an error
10921 rather than allowing the binlog to become corrupt.
10922 */
10923
3/4
✓ Branch 0 taken 7634 times.
✓ Branch 1 taken 23468348 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7634 times.
23475982 if (multi_write_engine && (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
10924 my_error((error = ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
10925 MYF(0));
10926
2/2
✓ Branch 0 taken 21115 times.
✓ Branch 1 taken 23454867 times.
23475982 else if (multi_access_engine &&
10927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21115 times.
21115 flags_access_some_set & HA_HAS_OWN_BINLOGGING)
10928 lex->set_stmt_unsafe(
10929 LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
10930
10931 /* XA is unsafe for statements */
10932
4/4
✓ Branch 0 taken 4723133 times.
✓ Branch 1 taken 18751884 times.
✓ Branch 2 taken 1039 times.
✓ Branch 3 taken 23474118 times.
28198290 if (is_write &&
10933
2/2
✓ Branch 0 taken 1039 times.
✓ Branch 1 taken 4722234 times.
4723133 !get_transaction()->xid_state()->has_state(XID_STATE::XA_NOTR))
10934
1/2
✓ Branch 0 taken 1039 times.
✗ Branch 1 not taken.
1039 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_XA);
10935
10936
3/4
✓ Branch 0 taken 23475322 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6030 times.
✓ Branch 3 taken 23469292 times.
23475157 DBUG_EXECUTE_IF("make_stmt_only_engines",
10937 { flags_write_all_set = HA_BINLOG_STMT_CAPABLE; };);
10938
10939 /* both statement-only and row-only engines involved */
10940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23475322 times.
23475322 if ((flags_write_all_set &
10941 (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) == 0) {
10942 /*
10943 1. Error: Binary logging impossible since both row-incapable
10944 engines and statement-incapable engines are involved
10945 */
10946 my_error((error = ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
10947 }
10948 /* statement-only engines involved */
10949
2/2
✓ Branch 0 taken 6036 times.
✓ Branch 1 taken 23469286 times.
23475322 else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0) {
10950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6036 times.
6036 if (lex->is_stmt_row_injection()) {
10951 /*
10952 4. Error: Cannot execute row injection since table uses
10953 storage engine limited to statement-logging
10954 */
10955 my_error((error = ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
10956
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6033 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6033 times.
6039 } else if (variables.binlog_format == BINLOG_FORMAT_ROW &&
10957
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 sqlcom_can_generate_row_events(this->lex->sql_command)) {
10958 /*
10959 2. Error: Cannot modify table that uses a storage engine
10960 limited to statement-logging when BINLOG_FORMAT = ROW
10961 */
10962
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 my_error((error = ER_BINLOG_ROW_MODE_AND_STMT_ENGINE), MYF(0));
10963
4/4
✓ Branch 0 taken 581 times.
✓ Branch 1 taken 5452 times.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 5856 times.
6614 } else if (variables.binlog_format == BINLOG_FORMAT_MIXED &&
10964
3/4
✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 404 times.
581 ((unsafe_flags = lex->get_stmt_unsafe_flags()) != 0)) {
10965 /*
10966 3. Error: Cannot execute statement: binlogging of unsafe
10967 statement is impossible when storage engine is limited to
10968 statement-logging and BINLOG_FORMAT = MIXED.
10969 */
10970
2/2
✓ Branch 0 taken 4602 times.
✓ Branch 1 taken 177 times.
4779 for (int unsafe_type = 0; unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
10971 unsafe_type++)
10972
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 4401 times.
4602 if (unsafe_flags & (1 << unsafe_type))
10973
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 my_error(
10974 (error = ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
10975
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 ER_THD_NONCONST(current_thd,
10976
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
10977
4/4
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 5514 times.
✓ Branch 2 taken 188 times.
✓ Branch 3 taken 5668 times.
6198 } else if (is_write &&
10978
3/4
✓ Branch 0 taken 342 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✓ Branch 3 taken 154 times.
342 ((unsafe_flags = lex->get_stmt_unsafe_flags()) != 0)) {
10979 /*
10980 7. Warning: Unsafe statement logged as statement due to
10981 binlog_format = STATEMENT
10982 */
10983 188 binlog_unsafe_warning_flags |= unsafe_flags;
10984
3/12
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 188 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
188 DBUG_PRINT("info", ("Scheduling warning to be issued by "
10985 "binlog_query: '%s'",
10986 ER_THD(current_thd, ER_BINLOG_UNSAFE_STATEMENT)));
10987
3/8
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 188 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
188 DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
10988 binlog_unsafe_warning_flags));
10989 }
10990 /* log in statement format! */
10991 }
10992 /* no statement-only engines */
10993 else {
10994 /* binlog_format = STATEMENT */
10995
2/2
✓ Branch 0 taken 2050662 times.
✓ Branch 1 taken 21418624 times.
23469286 if (variables.binlog_format == BINLOG_FORMAT_STMT) {
10996
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2050671 times.
2050662 if (lex->is_stmt_row_injection()) {
10997 /*
10998 6. Error: Cannot execute row injection since
10999 BINLOG_FORMAT = STATEMENT
11000 */
11001
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
6 my_error((error = ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
11002
3/4
✓ Branch 0 taken 1123 times.
✓ Branch 1 taken 2049548 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2050671 times.
2051794 } else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 &&
11003
2/4
✓ Branch 0 taken 1123 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1123 times.
1123 sqlcom_can_generate_row_events(this->lex->sql_command)) {
11004 /*
11005 5. Error: Cannot modify table that uses a storage engine
11006 limited to row-logging when binlog_format = STATEMENT
11007 */
11008 #ifdef WITH_WSREP
11009 if (!WSREP_NNULL(this) || wsrep_thd_is_local(this)) {
11010 my_error((error = ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
11011 }
11012 #else
11013 my_error((error = ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
11014 #endif /* WITH_WSREP */
11015
4/4
✓ Branch 0 taken 199171 times.
✓ Branch 1 taken 1851500 times.
✓ Branch 2 taken 13068 times.
✓ Branch 3 taken 2037807 times.
2250046 } else if (is_write &&
11016
3/4
✓ Branch 0 taken 199375 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13068 times.
✓ Branch 3 taken 186307 times.
199171 (unsafe_flags = lex->get_stmt_unsafe_flags()) != 0) {
11017 /*
11018 7. Warning: Unsafe statement logged as statement due to
11019 binlog_format = STATEMENT
11020 */
11021 13068 binlog_unsafe_warning_flags |= unsafe_flags;
11022
3/12
✓ Branch 0 taken 13068 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13068 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13068 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
13068 DBUG_PRINT("info", ("Scheduling warning to be issued by "
11023 "binlog_query: '%s'",
11024 ER_THD(current_thd, ER_BINLOG_UNSAFE_STATEMENT)));
11025
3/8
✓ Branch 0 taken 13068 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13068 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13068 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
13068 DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
11026 binlog_unsafe_warning_flags));
11027 }
11028 /* log in statement format! */
11029 }
11030 /* No statement-only engines and binlog_format != STATEMENT.
11031 I.e., nothing prevents us from row logging if needed. */
11032 else {
11033
5/6
✓ Branch 0 taken 21418657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19242334 times.
✓ Branch 3 taken 296798 times.
✓ Branch 4 taken 19241996 times.
✓ Branch 5 taken 366 times.
60200331 if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection() ||
11034 19242334 lex->is_stmt_unsafe_with_mixed_mode() ||
11035
2/2
✓ Branch 0 taken 19240826 times.
✓ Branch 1 taken 1170 times.
19241996 (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 ||
11036
3/4
✓ Branch 0 taken 19241260 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19138016 times.
✓ Branch 3 taken 103244 times.
19240826 lex->stmt_accessed_table(LEX::STMT_READS_TEMP_TRANS_TABLE) ||
11037
9/10
✓ Branch 0 taken 19539345 times.
✓ Branch 1 taken 1879312 times.
✓ Branch 2 taken 19138029 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19134778 times.
✓ Branch 5 taken 3251 times.
✓ Branch 6 taken 6416 times.
✓ Branch 7 taken 19128362 times.
✓ Branch 8 taken 2290611 times.
✓ Branch 9 taken 19128308 times.
40958251 lex->stmt_accessed_table(LEX::STMT_READS_TEMP_NON_TRANS_TABLE) ||
11038 is_create_drop_temp_table) {
11039 #ifndef NDEBUG
11040
1/2
✓ Branch 0 taken 2290745 times.
✗ Branch 1 not taken.
2290611 int flags = lex->get_stmt_unsafe_flags();
11041
5/8
✓ Branch 0 taken 2290705 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2290708 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2290703 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
2290745 DBUG_PRINT("info", ("setting row format for unsafe statement"));
11042
2/2
✓ Branch 0 taken 59551394 times.
✓ Branch 1 taken 2293668 times.
61845062 for (int i = 0; i < Query_tables_list::BINLOG_STMT_UNSAFE_COUNT;
11043 i++) {
11044
2/2
✓ Branch 0 taken 1909582 times.
✓ Branch 1 taken 57641812 times.
59551394 if (flags & (1 << i))
11045
7/12
✓ Branch 0 taken 1909574 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1909574 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1909569 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2974 times.
✗ Branch 11 not taken.
1909582 DBUG_PRINT(
11046 "info",
11047 ("unsafe reason: %s",
11048 ER_THD_NONCONST(
11049 current_thd,
11050 Query_tables_list::binlog_stmt_unsafe_errcode[i])));
11051 }
11052
5/8
✓ Branch 0 taken 2290685 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2290680 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2290675 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
2293668 DBUG_PRINT("info",
11053 ("is_row_injection=%d", lex->is_stmt_row_injection()));
11054
5/8
✓ Branch 0 taken 2290680 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2290678 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2290673 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
2290680 DBUG_PRINT("info", ("stmt_capable=%llu",
11055 (flags_write_all_set & HA_BINLOG_STMT_CAPABLE)));
11056
5/8
✓ Branch 0 taken 2290652 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2290667 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2290662 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
2290678 DBUG_PRINT("info", ("lex->is_stmt_unsafe_with_mixed_mode = %d",
11057 lex->is_stmt_unsafe_with_mixed_mode()));
11058 #endif
11059 /* log in row format! */
11060
1/2
✓ Branch 0 taken 2289543 times.
✗ Branch 1 not taken.
2290667 set_current_stmt_binlog_format_row_if_mixed();
11061 }
11062 }
11063 }
11064
11065
2/2
✓ Branch 0 taken 7925 times.
✓ Branch 1 taken 23466837 times.
23474762 if (non_replicated_tables_count > 0) {
11066
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 7787 times.
✓ Branch 2 taken 118 times.
✓ Branch 3 taken 20 times.
7925 if ((replicated_tables_count == 0) || !is_write) {
11067
3/8
✓ Branch 0 taken 7905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7905 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7905 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
7905 DBUG_PRINT("info",
11068 ("decision: no logging, no replicated table affected"));
11069 7905 set_binlog_local_stmt_filter();
11070 } else {
11071
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
20 if (!is_current_stmt_binlog_format_row()) {
11072
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 my_error((error = ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES), MYF(0));
11073 } else {
11074 12 clear_binlog_local_stmt_filter();
11075 }
11076 }
11077 } else {
11078 23466837 clear_binlog_local_stmt_filter();
11079 }
11080
11081
4/4
✓ Branch 0 taken 23474078 times.
✓ Branch 1 taken 233 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 23475516 times.
46949990 if (!error &&
11082
3/4
✓ Branch 0 taken 23475679 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 23475283 times.
23474078 !is_dml_gtid_compatible(write_to_some_transactional_table,
11083 write_to_some_non_transactional_table,
11084 write_all_non_transactional_are_tmp_tables))
11085 396 error = 1;
11086
11087
2/2
✓ Branch 0 taken 584 times.
✓ Branch 1 taken 23475328 times.
23475912 if (error) {
11088
3/8
✓ Branch 0 taken 584 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 584 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 584 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
584 DBUG_PRINT("info", ("decision: no logging since an error was generated"));
11089 584 return -1;
11090 }
11091
11092
2/2
✓ Branch 0 taken 4722801 times.
✓ Branch 1 taken 18752527 times.
23475328 if (is_write &&
11093
2/2
✓ Branch 0 taken 4425895 times.
✓ Branch 1 taken 296906 times.
4722801 lex->sql_command != SQLCOM_END /* rows-event applying by slave */) {
11094 /*
11095 Master side of DML in the STMT format events parallelization.
11096 All involving table db:s are stored in a abc-ordered name list.
11097 In case the number of databases exceeds MAX_DBS_IN_EVENT_MTS maximum
11098 the list gathering breaks since it won't be sent to the slave.
11099 */
11100
2/2
✓ Branch 0 taken 4829697 times.
✓ Branch 1 taken 4424298 times.
9253995 for (TABLE_LIST *table = tables; table; table = table->next_global) {
11101
2/2
✓ Branch 0 taken 12687 times.
✓ Branch 1 taken 4817350 times.
4829697 if (table->is_placeholder()) continue;
11102
11103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4817350 times.
4817350 assert(table->table);
11104
11105
2/2
✓ Branch 0 taken 1457 times.
✓ Branch 1 taken 4815102 times.
4817350 if (table->table->s->is_referenced_by_foreign_key()) {
11106 /*
11107 FK-referenced dbs can't be gathered currently. The following
11108 event will be marked for sequential execution on slave.
11109 */
11110 1457 binlog_accessed_db_names = nullptr;
11111
1/2
✓ Branch 0 taken 1457 times.
✗ Branch 1 not taken.
1457 add_to_binlog_accessed_dbs("");
11112 1457 break;
11113 }
11114
2/2
✓ Branch 0 taken 618140 times.
✓ Branch 1 taken 4197229 times.
4815102 if (!is_current_stmt_binlog_format_row())
11115
1/2
✓ Branch 0 taken 618184 times.
✗ Branch 1 not taken.
618140 add_to_binlog_accessed_dbs(table->db);
11116 }
11117 }
11118
7/10
✓ Branch 0 taken 23473765 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23474817 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 23474657 times.
✓ Branch 6 taken 126 times.
✓ Branch 7 taken 34 times.
✓ Branch 8 taken 160 times.
✗ Branch 9 not taken.
23475188 DBUG_PRINT("info",
11119 ("decision: logging in %s format",
11120 is_current_stmt_binlog_format_row() ? "ROW" : "STATEMENT"));
11121
11122
2/2
✓ Branch 0 taken 19514638 times.
✓ Branch 1 taken 3960179 times.
23474817 if (variables.binlog_format == BINLOG_FORMAT_ROW &&
11123
2/2
✓ Branch 0 taken 19373337 times.
✓ Branch 1 taken 141301 times.
19514638 (lex->sql_command == SQLCOM_UPDATE ||
11124
2/2
✓ Branch 0 taken 19371278 times.
✓ Branch 1 taken 2059 times.
19373337 lex->sql_command == SQLCOM_UPDATE_MULTI ||
11125
2/2
✓ Branch 0 taken 19316775 times.
✓ Branch 1 taken 54503 times.
19371278 lex->sql_command == SQLCOM_DELETE ||
11126
2/2
✓ Branch 0 taken 747 times.
✓ Branch 1 taken 19316028 times.
19316775 lex->sql_command == SQLCOM_DELETE_MULTI)) {
11127 198610 String table_names;
11128 /*
11129 Generate a warning for UPDATE/DELETE statements that modify a
11130 BLACKHOLE table, as row events are not logged in row format.
11131 */
11132
2/2
✓ Branch 0 taken 218795 times.
✓ Branch 1 taken 198789 times.
417584 for (TABLE_LIST *table = tables; table; table = table->next_global) {
11133
2/2
✓ Branch 0 taken 8701 times.
✓ Branch 1 taken 210141 times.
218795 if (table->is_placeholder()) continue;
11134
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 210137 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 210138 times.
210145 if (table->table->file->ht->db_type == DB_TYPE_BLACKHOLE_DB &&
11135
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE) {
11136
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 table_names.append(table->table_name);
11137
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 table_names.append(",");
11138 }
11139 }
11140
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 198681 times.
198789 if (!table_names.is_empty()) {
11141
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 bool is_update = (lex->sql_command == SQLCOM_UPDATE ||
11142
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 lex->sql_command == SQLCOM_UPDATE_MULTI);
11143 /*
11144 Replace the last ',' with '.' for table_names
11145 */
11146
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 table_names.replace(table_names.length() - 1, 1, ".", 1);
11147
5/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
3 push_warning_printf(
11148 this, Sql_condition::SL_WARNING, WARN_ON_BLOCKHOLE_IN_RBR,
11149 ER_THD(this, WARN_ON_BLOCKHOLE_IN_RBR),
11150 is_update ? "UPDATE" : "DELETE", table_names.c_ptr());
11151 }
11152 198684 }
11153 } else {
11154
5/10
✓ Branch 0 taken 6914273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6914642 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 6914639 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
6914629 DBUG_PRINT(
11155 "info",
11156 ("decision: no logging since "
11157 "mysql_bin_log.is_open() = %d "
11158 "and (options & OPTION_BIN_LOG) = 0x%llx "
11159 "and binlog_format = %lu "
11160 "and binlog_filter->db_ok(db) = %d",
11161 mysql_bin_log.is_open(), (variables.option_bits & OPTION_BIN_LOG),
11162 variables.binlog_format, binlog_filter->db_ok(m_db.str)));
11163
11164
2/2
✓ Branch 0 taken 6097521 times.
✓ Branch 1 taken 6914745 times.
13012266 for (TABLE_LIST *table = tables; table; table = table->next_global) {
11165
6/6
✓ Branch 0 taken 5590257 times.
✓ Branch 1 taken 507340 times.
✓ Branch 2 taken 940335 times.
✓ Branch 3 taken 4649922 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 6097656 times.
7037916 if (!table->is_placeholder() && table->table->no_replicate &&
11166
3/4
✓ Branch 0 taken 940395 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 940394 times.
940335 gtid_state->warn_or_err_on_modify_gtid_table(this, table))
11167 1 break;
11168 }
11169 }
11170
11171 #if defined(ENABLED_DEBUG_SYNC)
11172
3/4
✓ Branch 0 taken 30388342 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30347775 times.
✓ Branch 3 taken 40567 times.
30389638 if (!is_attachable_ro_transaction_active())
11173
3/4
✓ Branch 0 taken 28328935 times.
✓ Branch 1 taken 2018468 times.
✓ Branch 2 taken 28330999 times.
✗ Branch 3 not taken.
30347775 DEBUG_SYNC(this, "end_decide_logging_format");
11174 #endif
11175
11176 30390034 return 0;
11177 30390621 }
11178
11179 /**
11180 Given that a possible violation of gtid consistency has happened,
11181 checks if gtid-inconsistencies are forbidden by the current value of
11182 ENFORCE_GTID_CONSISTENCY and GTID_MODE. If forbidden, generates
11183 error or warning accordingly.
11184
11185 @param thd The thread that has issued the GTID-violating statement.
11186
11187 @param error_code The error code to use, if error or warning is to
11188 be generated.
11189
11190 @param log_error_code The error code to use, if error message is to
11191 be logged.
11192
11193 @retval false Error was generated.
11194 @retval true No error was generated (possibly a warning was generated).
11195 */
11196 11985 static bool handle_gtid_consistency_violation(THD *thd, int error_code,
11197 int log_error_code) {
11198
1/2
✓ Branch 0 taken 11985 times.
✗ Branch 1 not taken.
11985 DBUG_TRACE;
11199
11200 11985 enum_gtid_type gtid_next_type = thd->variables.gtid_next.type;
11201
1/2
✓ Branch 0 taken 11985 times.
✗ Branch 1 not taken.
11985 global_sid_lock->rdlock();
11202 enum_gtid_consistency_mode gtid_consistency_mode =
11203
1/2
✓ Branch 0 taken 11985 times.
✗ Branch 1 not taken.
11985 get_gtid_consistency_mode();
11204
1/2
✓ Branch 0 taken 11985 times.
✗ Branch 1 not taken.
11985 auto gtid_mode = global_gtid_mode.get();
11205
11206
7/12
✓ Branch 0 taken 11985 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11985 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 11979 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
11985 DBUG_PRINT("info", ("gtid_next.type=%d gtid_mode=%s "
11207 "gtid_consistency_mode=%d error=%d query=%s",
11208 gtid_next_type, Gtid_mode::to_string(gtid_mode),
11209 gtid_consistency_mode, error_code, thd->query().str));
11210
11211 /*
11212 GTID violations should generate error if:
11213 - GTID_MODE=ON or ON_PERMISSIVE and GTID_NEXT='AUTOMATIC' (since the
11214 transaction is expected to commit using a GTID), or
11215 - GTID_NEXT='UUID:NUMBER' (since the transaction is expected to
11216 commit usinga GTID), or
11217 - ENFORCE_GTID_CONSISTENCY=ON.
11218 */
11219
2/2
✓ Branch 0 taken 10632 times.
✓ Branch 1 taken 1353 times.
11985 if ((gtid_next_type == AUTOMATIC_GTID &&
11220
4/4
✓ Branch 0 taken 10291 times.
✓ Branch 1 taken 341 times.
✓ Branch 2 taken 11354 times.
✓ Branch 3 taken 290 times.
11985 gtid_mode >= Gtid_mode::ON_PERMISSIVE) ||
11221
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 11074 times.
11354 gtid_next_type == ASSIGNED_GTID ||
11222 gtid_consistency_mode == GTID_CONSISTENCY_MODE_ON) {
11223
1/2
✓ Branch 0 taken 911 times.
✗ Branch 1 not taken.
911 global_sid_lock->unlock();
11224
1/2
✓ Branch 0 taken 911 times.
✗ Branch 1 not taken.
911 my_error(error_code, MYF(0));
11225 911 return false;
11226 } else {
11227 /*
11228 If we are not generating an error, we must increase the counter
11229 of GTID-violating transactions. This will prevent a concurrent
11230 client from executing a SET GTID_MODE or SET
11231 ENFORCE_GTID_CONSISTENCY statement that would be incompatible
11232 with this transaction.
11233
11234 If the transaction had already been accounted as a gtid violating
11235 transaction, then don't increment the counters, just issue the
11236 warning below. This prevents calling
11237 begin_automatic_gtid_violating_transaction or
11238 begin_anonymous_gtid_violating_transaction multiple times for the
11239 same transaction, which would make the counter go out of sync.
11240 */
11241
2/2
✓ Branch 0 taken 9705 times.
✓ Branch 1 taken 1369 times.
11074 if (!thd->has_gtid_consistency_violation) {
11242
2/2
✓ Branch 0 taken 8906 times.
✓ Branch 1 taken 799 times.
9705 if (gtid_next_type == AUTOMATIC_GTID)
11243
1/2
✓ Branch 0 taken 8906 times.
✗ Branch 1 not taken.
8906 gtid_state->begin_automatic_gtid_violating_transaction();
11244 else {
11245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 799 times.
799 assert(gtid_next_type == ANONYMOUS_GTID);
11246
1/2
✓ Branch 0 taken 799 times.
✗ Branch 1 not taken.
799 gtid_state->begin_anonymous_gtid_violating_transaction();
11247 }
11248
11249 /*
11250 If a transaction generates multiple GTID violation conditions,
11251 it must still only update the counters once. Hence we use
11252 this per-thread flag to keep track of whether the thread has a
11253 consistency or not. This function must only be called if the
11254 transaction does not already have a GTID violation.
11255 */
11256 9705 thd->has_gtid_consistency_violation = true;
11257 }
11258
11259
1/2
✓ Branch 0 taken 11074 times.
✗ Branch 1 not taken.
11074 global_sid_lock->unlock();
11260
11261 // Generate warning if ENFORCE_GTID_CONSISTENCY = WARN.
11262
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 10786 times.
11074 if (gtid_consistency_mode == GTID_CONSISTENCY_MODE_WARN) {
11263 // Need to print to log so that replication admin knows when users
11264 // have adjusted their workloads.
11265
8/16
✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 288 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 288 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 288 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 288 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 288 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 288 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 288 times.
✗ Branch 15 not taken.
288 LogErr(WARNING_LEVEL, log_error_code);
11266 // Need to print to client so that users can adjust their workload.
11267
2/4
✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 288 times.
✗ Branch 3 not taken.
288 push_warning(thd, Sql_condition::SL_WARNING, error_code,
11268 ER_THD_NONCONST(thd, error_code));
11269 }
11270 11074 return true;
11271 }
11272 11985 }
11273
11274 21667527 bool THD::is_ddl_gtid_compatible() {
11275
1/2
✓ Branch 0 taken 21669182 times.
✗ Branch 1 not taken.
21667527 DBUG_TRACE;
11276
11277 21669182 bool is_binlog_open{mysql_bin_log.is_open()};
11278 21668745 bool is_binlog_enabled_for_session{(variables.option_bits & OPTION_BIN_LOG) !=
11279 0};
11280
4/8
✓ Branch 0 taken 21668858 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21668959 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 205 times.
✓ Branch 5 taken 21668754 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
21668745 DBUG_PRINT("info", ("is_binlog_open:%d is_binlog_enabled_for_session:%d",
11281 is_binlog_open, is_binlog_enabled_for_session));
11282 // If we are not going to log, then no problem, we can execute any
11283 // statement.
11284
4/4
✓ Branch 0 taken 16953825 times.
✓ Branch 1 taken 4714364 times.
✓ Branch 2 taken 1143387 times.
✓ Branch 3 taken 15810438 times.
21668189 if (!is_binlog_open || !is_binlog_enabled_for_session) return true;
11285
11286 15810438 bool is_create_table{lex->sql_command == SQLCOM_CREATE_TABLE};
11287 15810438 bool is_create_temporary_table{false};
11288 15810438 bool is_create_table_select{false};
11289 15810438 bool is_create_table_atomic{false};
11290
2/2
✓ Branch 0 taken 145063 times.
✓ Branch 1 taken 15665375 times.
15810438 if (is_create_table) {
11291 // Check this conditionally, since create_info and/or query_block
11292 // may be uninitialized if sql_command!=SQLCOM_CREATE_TABLE.
11293 145063 is_create_temporary_table =
11294 145063 (lex->create_info->options & HA_LEX_CREATE_TMP_TABLE);
11295
2/2
✓ Branch 0 taken 135927 times.
✓ Branch 1 taken 9136 times.
145063 if (!is_create_temporary_table)
11296
1/2
✓ Branch 0 taken 135927 times.
✗ Branch 1 not taken.
135927 is_create_table_select = !lex->query_block->field_list_is_empty();
11297 145063 is_create_table_atomic =
11298
1/2
✓ Branch 0 taken 145063 times.
✗ Branch 1 not taken.
145063 get_default_handlerton(this, lex->create_info->db_type)->flags &
11299 HTON_SUPPORTS_ATOMIC_DDL;
11300 }
11301
11302 15810438 bool is_drop_table{lex->sql_command == SQLCOM_DROP_TABLE};
11303 15810438 bool is_drop_temporary_table{false};
11304
2/2
✓ Branch 0 taken 106379 times.
✓ Branch 1 taken 15704059 times.
15810438 if (is_drop_table) is_drop_temporary_table = lex->drop_temporary;
11305
11306 15810438 bool is_in_transaction{in_multi_stmt_transaction_mode()};
11307
11308 15810162 bool is_in_sub_statement{in_sub_stmt != 0};
11309
11310 15810162 bool is_binlog_format_statement{variables.binlog_format ==
11311 BINLOG_FORMAT_STMT};
11312
11313
5/8
✓ Branch 0 taken 15810894 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15810630 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 203 times.
✓ Branch 5 taken 15810427 times.
✓ Branch 6 taken 203 times.
✗ Branch 7 not taken.
15810162 DBUG_PRINT("info", ("is_create_table:%d is_create_temporary_table:%d "
11314 "is_create_table_select:%d is_create_table_atomic:%d "
11315 "is_drop_table:%d is_drop_temporary_table:%d "
11316 "is_in_transaction:%d is_in_sub_statement:%d "
11317 "is_binlog_format_statement:%d",
11318 is_create_table, is_create_temporary_table,
11319 is_create_table_select, is_create_table_atomic,
11320 is_drop_table, is_drop_temporary_table, is_in_transaction,
11321 is_in_sub_statement, is_binlog_format_statement));
11322
11323
3/4
✓ Branch 0 taken 10077 times.
✓ Branch 1 taken 15800553 times.
✓ Branch 2 taken 10077 times.
✗ Branch 3 not taken.
15810630 if (is_create_table_select && !is_create_temporary_table &&
11324
2/2
✓ Branch 0 taken 3321 times.
✓ Branch 1 taken 6756 times.
10077 !is_create_table_atomic) {
11325 /*
11326 CREATE ... SELECT (without TEMPORARY) for engines not supporting
11327 atomic DDL is unsafe because if binlog_format=row it will be
11328 logged as a CREATE TABLE followed by row events, re-executed
11329 non-atomically as two transactions, and then written to the
11330 slave's binary log as two separate transactions with the same
11331 GTID.
11332 */
11333
1/2
✓ Branch 0 taken 3321 times.
✗ Branch 1 not taken.
3321 return handle_gtid_consistency_violation(
11334 this, ER_GTID_UNSAFE_CREATE_SELECT,
11335 3321 ER_RPL_GTID_UNSAFE_STMT_CREATE_SELECT);
11336 }
11337
11338
6/6
✓ Branch 0 taken 15797362 times.
✓ Branch 1 taken 9947 times.
✓ Branch 2 taken 5956 times.
✓ Branch 3 taken 15791406 times.
✓ Branch 4 taken 3822 times.
✓ Branch 5 taken 12081 times.
15807309 if ((is_create_temporary_table || is_drop_temporary_table) &&
11339
2/2
✓ Branch 0 taken 3336 times.
✓ Branch 1 taken 486 times.
3822 is_binlog_format_statement &&
11340
2/2
✓ Branch 0 taken 608 times.
✓ Branch 1 taken 2728 times.
3336 (is_in_transaction || is_in_sub_statement)) {
11341 /*
11342 When @@session.binlog_format=statement,
11343 [CREATE|DROP] TEMPORARY TABLE is unsafe to execute inside a
11344 transaction or Procedure, because the [CREATE|DROP] statement on
11345 the temporary table will be executed and written into binary log
11346 with a GTID even if the transaction or Procedure is rolled back.
11347 */
11348
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
1094 return handle_gtid_consistency_violation(
11349 this, ER_CLIENT_GTID_UNSAFE_CREATE_DROP_TEMP_TABLE_IN_TRX_IN_SBR,
11350 486 ER_SERVER_GTID_UNSAFE_CREATE_DROP_TEMP_TABLE_IN_TRX_IN_SBR);
11351 }
11352
11353 15806215 return true;
11354 21667773 }
11355
11356 23473875 bool THD::is_dml_gtid_compatible(bool some_transactional_table,
11357 bool some_non_transactional_table,
11358 bool non_transactional_tables_are_tmp) {
11359
1/2
✓ Branch 0 taken 23475669 times.
✗ Branch 1 not taken.
23473875 DBUG_TRACE;
11360
11361 // If @@session.sql_log_bin has been manually turned off (only
11362 // doable by SUPER), then no problem, we can execute any statement.
11363
4/4
✓ Branch 0 taken 23474620 times.
✓ Branch 1 taken 1049 times.
✓ Branch 2 taken 3205 times.
✓ Branch 3 taken 23472005 times.
46949830 if ((variables.option_bits & OPTION_BIN_LOG) == 0 ||
11364
2/2
✓ Branch 0 taken 2156 times.
✓ Branch 1 taken 23472005 times.
23474620 mysql_bin_log.is_open() == false)
11365 3205 return true;
11366
11367 /*
11368 Single non-transactional updates are allowed when not mixed
11369 together with transactional statements within a transaction.
11370 Furthermore, writing to transactional and non-transactional
11371 engines in a single statement is also disallowed.
11372 Multi-statement transactions on non-transactional tables are
11373 split into single-statement transactions when
11374 GTID_NEXT = "AUTOMATIC".
11375
11376 Non-transactional updates are allowed when row binlog format is
11377 used and all non-transactional tables are temporary.
11378
11379 The debug symbol "allow_gtid_unsafe_non_transactional_updates"
11380 disables the error. This is useful because it allows us to run
11381 old tests that were not written with the restrictions of GTIDs in
11382 mind.
11383 */
11384
6/10
✓ Branch 0 taken 23472084 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23472170 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 23472010 times.
✓ Branch 6 taken 160 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 160 times.
✗ Branch 9 not taken.
23472005 DBUG_PRINT("info", ("some_non_transactional_table=%d "
11385 "some_transactional_table=%d "
11386 "trans_has_updated_trans_table=%d "
11387 "non_transactional_tables_are_tmp=%d "
11388 "is_current_stmt_binlog_format_row=%d",
11389 some_non_transactional_table, some_transactional_table,
11390 trans_has_updated_trans_table(this),
11391 non_transactional_tables_are_tmp,
11392 is_current_stmt_binlog_format_row()));
11393
2/2
✓ Branch 0 taken 406678 times.
✓ Branch 1 taken 6323 times.
413001 if (some_non_transactional_table &&
11394
3/4
✓ Branch 0 taken 406716 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2180 times.
✓ Branch 3 taken 404536 times.
406678 (some_transactional_table || trans_has_updated_trans_table(this)) &&
11395
3/4
✓ Branch 0 taken 568 times.
✓ Branch 1 taken 7935 times.
✓ Branch 2 taken 1235 times.
✗ Branch 3 not taken.
9071 !(non_transactional_tables_are_tmp &&
11396
4/4
✓ Branch 0 taken 413001 times.
✓ Branch 1 taken 23059169 times.
✓ Branch 2 taken 8178 times.
✓ Branch 3 taken 23463038 times.
23884785 is_current_stmt_binlog_format_row()) &&
11397
2/4
✓ Branch 0 taken 8178 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8178 times.
✗ Branch 3 not taken.
9170 !DBUG_EVALUATE_IF("allow_gtid_unsafe_non_transactional_updates", 1, 0)) {
11398
1/2
✓ Branch 0 taken 8178 times.
✗ Branch 1 not taken.
8178 return handle_gtid_consistency_violation(
11399 this, ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE,
11400 8178 ER_RPL_GTID_UNSAFE_STMT_ON_NON_TRANS_TABLE);
11401 }
11402
11403 23463038 return true;
11404 23474421 }
11405
11406 /*
11407 Implementation of interface to write rows to the binary log through the
11408 thread. The thread is responsible for writing the rows it has
11409 inserted/updated/deleted.
11410 */
11411
11412 /*
11413 Template member function for ensuring that there is an rows log
11414 event of the appropriate type before proceeding.
11415
11416 PRE CONDITION:
11417 - Events of type 'RowEventT' have the type code 'type_code'.
11418
11419 POST CONDITION:
11420 If a non-NULL pointer is returned, the pending event for thread 'thd' will
11421 be an event of type 'RowEventT' (which have the type code 'type_code')
11422 will either empty or have enough space to hold 'needed' bytes. In
11423 addition, the columns bitmap will be correct for the row, meaning that
11424 the pending event will be flushed if the columns in the event differ from
11425 the columns suppled to the function.
11426
11427 RETURNS
11428 If no error, a non-NULL pending event (either one which already existed or
11429 the newly created one).
11430 If error, NULL.
11431 */
11432
11433 template <class RowsEventT>
11434 95453912 Rows_log_event *THD::binlog_prepare_pending_rows_event(
11435 TABLE *table, uint32 serv_id, size_t needed, bool is_transactional,
11436 const unsigned char *extra_row_info, uint32 source_part_id) {
11437
1/2
✓ Branch 0 taken 47727165 times.
✗ Branch 1 not taken.
95453912 DBUG_TRACE;
11438
11439
3/4
✓ Branch 0 taken 47727024 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 47727018 times.
95454330 DBUG_EXECUTE_IF("simulate_null_pending_rows_event", { return nullptr; });
11440
11441 /* Fetch the type code for the RowsEventT template parameter */
11442 95454036 int const general_type_code = RowsEventT::TYPE_CODE;
11443
11444 95454036 partition_info *part_info = table->part_info;
11445
1/2
✓ Branch 0 taken 47726618 times.
✗ Branch 1 not taken.
95454036 auto part_id = get_rpl_part_id(part_info);
11446
11447
1/2
✓ Branch 0 taken 47727029 times.
✗ Branch 1 not taken.
95453236 Rows_log_event *pending = binlog_get_pending_rows_event(is_transactional);
11448
11449
5/8
✓ Branch 0 taken 43488855 times.
✓ Branch 1 taken 4238174 times.
✓ Branch 2 taken 43488777 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 43488777 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 47726907 times.
95454058 if (unlikely(pending && !pending->is_valid())) return nullptr;
11450
11451 /*
11452 Check if the current event is non-NULL and a write-rows
11453 event. Also check if the table provided is mapped: if it is not,
11454 then we have switched to writing to a new table.
11455 If there is no pending event, we need to create one. If there is a pending
11456 event, but it's not about the same table id, or not of the same type
11457 (between Write, Update and Delete), or not the same affected columns, or
11458 going to be too big, flush this event to disk and create a new pending
11459 event.
11460
11461 We do not need to check that the pending event and the new event
11462 have the same setting for partial json updates, because
11463 partialness of json can only be changed outside transactions.
11464 */
11465
3/4
✓ Branch 0 taken 43488747 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43481020 times.
✓ Branch 3 taken 7696 times.
173954922 if (!pending || pending->server_id != serv_id ||
11466 86977494 pending->get_table_id() != table->s->table_map_id ||
11467
3/4
✓ Branch 0 taken 43480874 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43480317 times.
✓ Branch 3 taken 557 times.
86962040 pending->get_general_type_code() != general_type_code ||
11468
3/4
✓ Branch 0 taken 43480510 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43250408 times.
✓ Branch 3 taken 230102 times.
86960634 pending->get_data_size() + needed > binlog_row_event_max_size ||
11469
7/8
✓ Branch 0 taken 43488745 times.
✓ Branch 1 taken 4238162 times.
✓ Branch 2 taken 43250149 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43250128 times.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 4641438 times.
✓ Branch 7 taken 43085407 times.
268931954 pending->read_write_bitmaps_cmp(table) == false ||
11470
3/4
✓ Branch 0 taken 43250309 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164884 times.
✓ Branch 3 taken 43085425 times.
86500256 !(pending->m_extra_row_info.compare_extra_row_info(
11471 extra_row_info, part_id, source_part_id))) {
11472 /* Create a new RowsEventT... */
11473
1/2
✓ Branch 0 taken 4641641 times.
✗ Branch 1 not taken.
9282876 Rows_log_event *const ev = new RowsEventT(
11474
1/2
✓ Branch 0 taken 4641580 times.
✗ Branch 1 not taken.
9283282 this, table, table->s->table_map_id, is_transactional, extra_row_info);
11475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4641581 times.
9283160 if (unlikely(!ev)) return nullptr;
11476 9283162 ev->server_id = serv_id; // I don't like this, it's too easy to forget.
11477 /*
11478 flush the pending event and replace it with the newly created
11479 event...
11480 */
11481
2/4
✓ Branch 0 taken 4641623 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4641594 times.
9283162 if (unlikely(mysql_bin_log.flush_and_set_pending_rows_event(
11482 this, ev, is_transactional))) {
11483 delete ev;
11484 4 return nullptr;
11485 }
11486
11487 9283188 return ev; /* This is the new pending event */
11488 }
11489 86170814 return pending; /* This is the current pending event */
11490 95454018 }
11491
11492 /* Declare in unnamed namespace. */
11493 namespace {
11494
11495 /**
11496 Class to handle temporary allocation of memory for row data.
11497
11498 The responsibilities of the class is to provide memory for
11499 packing one or two rows of packed data (depending on what
11500 constructor is called).
11501
11502 In order to make the allocation more efficient for rows without blobs,
11503 a pointer to the allocated memory is stored in the table structure
11504 for such rows. If memory for a table containing a blob field
11505 is requested, only memory for that is allocated, and subsequently
11506 released when the object is destroyed.
11507
11508 */
11509 class Row_data_memory {
11510 public:
11511 /**
11512 Build an object to keep track of a block-local piece of memory
11513 for storing a row of data.
11514
11515 @param table
11516 Table where the pre-allocated memory is stored.
11517
11518 @param data
11519 Pointer to the table record.
11520 */
11521 43910900 Row_data_memory(TABLE *table, const uchar *data) : m_memory(nullptr) {
11522 #ifndef NDEBUG
11523 43910900 m_alloc_checked = false;
11524 #endif
11525 43910900 allocate_memory(table, max_row_length(table, data));
11526
1/2
✓ Branch 0 taken 43911398 times.
✗ Branch 1 not taken.
43911614 m_ptr[0] = has_memory() ? m_memory : nullptr;
11527 43911398 m_ptr[1] = nullptr;
11528 43911398 }
11529
11530 3815524 Row_data_memory(TABLE *table, const uchar *data1, const uchar *data2,
11531 ulonglong value_options = 0)
11532 3815524 : m_memory(nullptr) {
11533 #ifndef NDEBUG
11534 3815524 m_alloc_checked = false;
11535 #endif
11536 3815524 size_t len1 = max_row_length(table, data1);
11537 3815525 size_t len2 = max_row_length(table, data2, value_options);
11538 3815525 allocate_memory(table, len1 + len2);
11539
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815525 m_ptr[0] = has_memory() ? m_memory : nullptr;
11540
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815525 m_ptr[1] = has_memory() ? m_memory + len1 : nullptr;
11541 3815525 }
11542
11543 47726897 ~Row_data_memory() {
11544
3/4
✓ Branch 0 taken 47727030 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3078585 times.
✓ Branch 3 taken 44648445 times.
47726897 if (m_memory != nullptr && m_release_memory_on_destruction)
11545 3078585 my_free(m_memory);
11546 47726902 }
11547
11548 /**
11549 Is there memory allocated?
11550
11551 @retval true There is memory allocated
11552 @retval false Memory allocation failed
11553 */
11554 99269259 bool has_memory() const {
11555 #ifndef NDEBUG
11556 99269259 m_alloc_checked = true;
11557 #endif
11558 99269259 return m_memory != nullptr;
11559 }
11560
11561 51542474 uchar *slot(uint s) {
11562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51542474 times.
51542474 assert(s < sizeof(m_ptr) / sizeof(*m_ptr));
11563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51542474 times.
51542474 assert(m_ptr[s] != nullptr);
11564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51542474 times.
51542474 assert(m_alloc_checked == true);
11565 51542474 return m_ptr[s];
11566 }
11567
11568 private:
11569 /**
11570 Compute an upper bound on the amount of memory needed.
11571
11572 This may return an over-approximation.
11573
11574 @param table The table
11575 @param data The server's row record.
11576 @param value_options The value of @@global.binlog_row_value_options
11577 */
11578 51541798 size_t max_row_length(TABLE *table, const uchar *data,
11579 ulonglong value_options = 0) {
11580 51541798 TABLE_SHARE *table_s = table->s;
11581
1/2
✓ Branch 0 taken 51542658 times.
✗ Branch 1 not taken.
51541798 Replicated_columns_view fields{table, Replicated_columns_view::OUTBOUND};
11582 /*
11583 The server stores rows using "records". A record is a sequence of bytes
11584 which contains values or pointers to values for all fields (columns). The
11585 server uses table_s->reclength bytes for a row record.
11586
11587 The layout of a record is roughly:
11588
11589 - N+1+B bits, packed into CEIL((N+1+B)/8) bytes, where N is the number of
11590 nullable columns in the table, and B is the sum of the number of bits of
11591 all BIT columns.
11592
11593 - A sequence of serialized fields, each corresponding to a non-BIT,
11594 non-NULL column in the table.
11595
11596 For variable-length columns, the first component of the serialized field
11597 is a length, stored using 1, 2, 3, or 4 bytes depending on the maximum
11598 length for the data type.
11599
11600 For most data types, the next component of the serialized field is the
11601 actual data. But for for VARCHAR, VARBINARY, TEXT, BLOB, and JSON, the
11602 next component of the serialized field is a serialized pointer,
11603 i.e. sizeof(pointer) bytes, which point to another memory area where the
11604 actual data is stored.
11605
11606 The layout of a row image in the binary log is roughly:
11607
11608 - If this is an after-image and partial JSON is enabled, 1 byte containing
11609 value_options. If the PARTIAL_JSON bit of value_options is set, this is
11610 followed by P bits (the "partial_bits"), packed into CEIL(P) bytes,
11611 where P is the number of JSON columns in the table.
11612
11613 - M bits (the "null_bits"), packed into CEIL(M) bytes, where M is the
11614 number of columns in the image.
11615
11616 - A sequence of serialized fields, each corresponding to a non-NULL column
11617 in the row image.
11618
11619 For variable-length columns, the first component of the serialized field
11620 is a length, stored using 1, 2, 3, or 4 bytes depending on the maximum
11621 length for the data type.
11622
11623 For most data types, the next component of the serialized field is the
11624 actual field data. But for JSON fields where the corresponding bit of
11625 the partial_bits is 1, this is a sequence of diffs instead.
11626
11627 Now we try to use table_s->reclength to estimate how much memory to
11628 allocate for a row image in the binlog. Due to the differences this will
11629 only be an upper bound. Notice the differences:
11630
11631 - The binlog may only include a subset of the fields (the row image),
11632 whereas reclength contains space for all fields.
11633
11634 - BIT columns are not packed together with NULL bits in the binlog, so up
11635 to 1 more byte per BIT column may be needed.
11636
11637 - The binlog has a null bit even for non-nullable fields, whereas the
11638 reclength only contains space nullable fields, so the binlog may need up
11639 to CEIL(table_s->fields/8) more bytes.
11640
11641 - The binlog only has a null bit for fields in the image, whereas the
11642 reclength contains space for all fields.
11643
11644 - The binlog contains the full blob whereas the record only contains
11645 sizeof(pointer) bytes.
11646
11647 - The binlog contains value_options and partial_bits. So this may use up
11648 to 1+CEIL(table_s->fields/8) more bytes.
11649
11650 - The binlog may contain partial JSON. This is guaranteed to be smaller
11651 than the size of the full value.
11652
11653 - There may exist columns that, due to their nature, are not replicated,
11654 for instance, hidden generated columns used for functional indexes.
11655
11656 For those data types that are not stored using a pointer, the size of the
11657 field in the binary log is at most 2 bytes more than what the field
11658 contributes to in table_s->reclength, because those data types use at most
11659 1 byte for the length and waste less than a byte on extra padding and
11660 extra bits in null_bits or BIT columns.
11661
11662 For those data types that are stored using a pointer, the size of the
11663 field in the binary log is at most 2 bytes more than what the field
11664 contributes to in table_s->reclength, plus the size of the data. The size
11665 of the pointer is at least 4 on all supported platforms, so it is bigger
11666 than what is used by partial_bits, value_format, or any waste due to extra
11667 padding and extra bits in null_bits.
11668 */
11669 51542658 size_t length = table_s->reclength + 2 * (fields.filtered_size());
11670
11671
2/2
✓ Branch 0 taken 6157011 times.
✓ Branch 1 taken 51542067 times.
57699078 for (uint i = 0; i < table_s->blob_fields; i++) {
11672
2/2
✓ Branch 0 taken 1288 times.
✓ Branch 1 taken 6155724 times.
6157011 if (fields.is_excluded(table_s->blob_field[i])) continue;
11673
11674 6155724 Field *field = table->field[table_s->blob_field[i]];
11675 6155724 Field_blob *field_blob = down_cast<Field_blob *>(field);
11676
11677
5/6
✓ Branch 0 taken 6155720 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 193476 times.
✓ Branch 3 taken 5962244 times.
✓ Branch 4 taken 8939 times.
✓ Branch 5 taken 6146781 times.
6349151 if (field_blob->type() == MYSQL_TYPE_JSON &&
11678
2/2
✓ Branch 0 taken 8939 times.
✓ Branch 1 taken 184537 times.
193476 (value_options & PARTIAL_JSON_UPDATES) != 0) {
11679 8939 Field_json *field_json = down_cast<Field_json *>(field_blob);
11680
1/2
✓ Branch 0 taken 8939 times.
✗ Branch 1 not taken.
8939 length += field_json->get_diff_vector_and_length(value_options);
11681 } else
11682 6146785 length +=
11683
1/2
✓ Branch 0 taken 6146785 times.
✗ Branch 1 not taken.
6146781 field_blob->get_length(data + field_blob->offset(table->record[0]));
11684 }
11685 51542709 return length;
11686 51542067 }
11687
11688 47727054 void allocate_memory(TABLE *const table, const size_t total_length) {
11689
2/2
✓ Branch 0 taken 44648506 times.
✓ Branch 1 taken 3078548 times.
47727054 if (table->s->blob_fields == 0) {
11690 /*
11691 The maximum length of a packed record is less than this
11692 length. We use this value instead of the supplied length
11693 when allocating memory for records, since we don't know how
11694 the memory will be used in future allocations.
11695
11696 Since table->s->reclength is for unpacked records, we have
11697 to add two bytes for each field, which can potentially be
11698 added to hold the length of a packed field.
11699 */
11700 44648506 size_t const maxlen = table->s->reclength + 2 * table->s->fields;
11701
11702 /*
11703 Allocate memory for two records if memory hasn't been
11704 allocated. We allocate memory for two records so that it can
11705 be used when processing update rows as well.
11706 */
11707
2/2
✓ Branch 0 taken 115520 times.
✓ Branch 1 taken 44532986 times.
44648506 if (table->write_row_record == nullptr)
11708 115520 table->write_row_record = (uchar *)table->mem_root.Alloc(2 * maxlen);
11709 44648507 m_memory = table->write_row_record;
11710 44648507 m_release_memory_on_destruction = false;
11711 } else {
11712 3078548 m_memory = (uchar *)my_malloc(key_memory_Row_data_memory_memory,
11713 total_length, MYF(MY_WME));
11714 3078590 m_release_memory_on_destruction = true;
11715 }
11716 47727097 }
11717
11718 #ifndef NDEBUG
11719 mutable bool m_alloc_checked;
11720 #endif
11721 bool m_release_memory_on_destruction;
11722 uchar *m_memory;
11723 uchar *m_ptr[2];
11724 };
11725
11726 } // namespace
11727
11728 41827243 int THD::binlog_write_row(TABLE *table, bool is_trans, uchar const *record,
11729 const unsigned char *extra_row_info) {
11730 #ifdef WITH_WSREP
11731
11/12
✓ Branch 0 taken 41827837 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5430010 times.
✓ Branch 3 taken 36397827 times.
✓ Branch 4 taken 5430008 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 5430005 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 5334944 times.
✓ Branch 9 taken 95061 times.
✓ Branch 10 taken 41732815 times.
✓ Branch 11 taken 18 times.
41827243 assert(is_current_stmt_binlog_format_row() &&
11732 ((WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open())));
11733 #else
11734 assert(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
11735 #endif /* WITH_WSREP */
11736
11737 /*
11738 Pack records into format for transfer. We are allocating more
11739 memory than needed, but that doesn't matter.
11740 */
11741
1/2
✓ Branch 0 taken 41827768 times.
✗ Branch 1 not taken.
41827876 Row_data_memory memory(table, record);
11742
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41827808 times.
41827768 if (!memory.has_memory()) return HA_ERR_OUT_OF_MEM;
11743
11744 41827808 uchar *row_data = memory.slot(0);
11745
11746
1/2
✓ Branch 0 taken 41827866 times.
✗ Branch 1 not taken.
41827819 size_t const len = pack_row(table, table->write_set, row_data, record,
11747 enum_row_image_type::WRITE_AI);
11748
11749 Rows_log_event *const ev =
11750
1/2
✓ Branch 0 taken 41827914 times.
✗ Branch 1 not taken.
41827866 binlog_prepare_pending_rows_event<Write_rows_log_event>(
11751 table, server_id, len, is_trans, extra_row_info);
11752
11753
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 41827887 times.
41827914 if (unlikely(ev == nullptr)) return HA_ERR_OUT_OF_MEM;
11754
11755
1/2
✓ Branch 0 taken 41827946 times.
✗ Branch 1 not taken.
41827887 return ev->add_row_data(row_data, len);
11756 41827950 }
11757
11758 3815524 int THD::binlog_update_row(TABLE *table, bool is_trans,
11759 const uchar *before_record,
11760 const uchar *after_record,
11761 const unsigned char *extra_row_info) {
11762 #ifdef WITH_WSREP
11763
8/12
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1014157 times.
✓ Branch 3 taken 2801368 times.
✓ Branch 4 taken 1014157 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1014157 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1014141 times.
✓ Branch 9 taken 16 times.
✓ Branch 10 taken 3815509 times.
✗ Branch 11 not taken.
3815524 assert(is_current_stmt_binlog_format_row() &&
11764 ((WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open())));
11765 #else
11766 assert(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
11767 #endif /* WITH_WSREP */
11768
11769 3815525 int error = 0;
11770
11771 /**
11772 Save a reference to the original read and write set bitmaps.
11773 We will need this to restore the bitmaps at the end.
11774 */
11775 3815525 MY_BITMAP *old_read_set = table->read_set;
11776 3815525 MY_BITMAP *old_write_set = table->write_set;
11777
11778 /**
11779 This will remove spurious fields required during execution but
11780 not needed for binlogging. This is done according to the:
11781 binlog-row-image option.
11782 */
11783
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815525 binlog_prepare_row_images(this, table);
11784
11785 Row_data_memory row_data(table, before_record, after_record,
11786
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815525 variables.binlog_row_value_options);
11787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3815525 times.
3815525 if (!row_data.has_memory()) return HA_ERR_OUT_OF_MEM;
11788
11789 3815525 uchar *before_row = row_data.slot(0);
11790 3815525 uchar *after_row = row_data.slot(1);
11791
11792 size_t const before_size =
11793
1/2
✓ Branch 0 taken 3815523 times.
✗ Branch 1 not taken.
3815525 pack_row(table, table->read_set, before_row, before_record,
11794 enum_row_image_type::UPDATE_BI);
11795 7631048 size_t const after_size = pack_row(
11796
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815523 table, table->write_set, after_row, after_record,
11797 enum_row_image_type::UPDATE_AI, variables.binlog_row_value_options);
11798
11799
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815525 DBUG_DUMP("before_record", before_record, table->s->reclength);
11800
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815525 DBUG_DUMP("after_record", after_record, table->s->reclength);
11801
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815525 DBUG_DUMP("before_row", before_row, before_size);
11802
1/2
✓ Branch 0 taken 3815525 times.
✗ Branch 1 not taken.
3815525 DBUG_DUMP("after_row", after_row, after_size);
11803
11804 3815525 partition_info *part_info = table->part_info;
11805 3815525 uint32 source_part_id = binary_log::Rows_event::Extra_row_info::UNDEFINED;
11806
2/2
✓ Branch 0 taken 116646 times.
✓ Branch 1 taken 3698879 times.
3815525 if (part_info) {
11807 116646 uint32 new_part_id = binary_log::Rows_event::Extra_row_info::UNDEFINED;
11808 116646 longlong func_value = 0;
11809
1/2
✓ Branch 0 taken 116646 times.
✗ Branch 1 not taken.
116646 get_parts_for_update(before_record, after_record, table->record[0],
11810 part_info, &source_part_id, &new_part_id, &func_value);
11811 }
11812
11813 Rows_log_event *const ev =
11814
1/2
✓ Branch 0 taken 3815523 times.
✗ Branch 1 not taken.
3815525 binlog_prepare_pending_rows_event<Update_rows_log_event>(
11815 table, server_id, before_size + after_size, is_trans, extra_row_info,
11816 source_part_id);
11817
11818
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3815522 times.
3815523 if (unlikely(ev == nullptr)) return HA_ERR_OUT_OF_MEM;
11819
11820
2/2
✓ Branch 0 taken 116645 times.
✓ Branch 1 taken 3698877 times.
3815522 if (part_info) {
11821 116645 ev->m_extra_row_info.set_source_partition_id(source_part_id);
11822 }
11823
11824
3/4
✓ Branch 0 taken 3815523 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3815522 times.
✓ Branch 3 taken 1 times.
7631045 error = ev->add_row_data(before_row, before_size) ||
11825
2/4
✓ Branch 0 taken 3815523 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3815523 times.
3815522 ev->add_row_data(after_row, after_size);
11826
11827 /* restore read/write set for the rest of execution */
11828 3815524 table->column_bitmaps_set_no_signal(old_read_set, old_write_set);
11829
11830 3815519 bitmap_clear_all(&table->tmp_set);
11831
11832 3815521 return error;
11833 3815523 }
11834
11835 2083635 int THD::binlog_delete_row(TABLE *table, bool is_trans, uchar const *record,
11836 const unsigned char *extra_row_info) {
11837 #ifdef WITH_WSREP
11838
8/12
✓ Branch 0 taken 2083635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24368 times.
✓ Branch 3 taken 2059267 times.
✓ Branch 4 taken 24368 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24368 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24366 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 2083633 times.
✗ Branch 11 not taken.
2083635 assert(is_current_stmt_binlog_format_row() &&
11839 ((WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open())));
11840 #else
11841 assert(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
11842 #endif /* WITH_WSREP */
11843
11844 2083635 int error = 0;
11845
11846 /**
11847 Save a reference to the original read and write set bitmaps.
11848 We will need this to restore the bitmaps at the end.
11849 */
11850 2083635 MY_BITMAP *old_read_set = table->read_set;
11851 2083635 MY_BITMAP *old_write_set = table->write_set;
11852
11853 /**
11854 This will remove spurious fields required during execution but
11855 not needed for binlogging. This is done according to the:
11856 binlog-row-image option.
11857 */
11858
1/2
✓ Branch 0 taken 2083635 times.
✗ Branch 1 not taken.
2083635 binlog_prepare_row_images(this, table);
11859
11860 /*
11861 Pack records into format for transfer. We are allocating more
11862 memory than needed, but that doesn't matter.
11863 */
11864
1/2
✓ Branch 0 taken 2083635 times.
✗ Branch 1 not taken.
2083635 Row_data_memory memory(table, record);
11865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2083635 times.
2083635 if (unlikely(!memory.has_memory())) return HA_ERR_OUT_OF_MEM;
11866
11867 2083635 uchar *row_data = memory.slot(0);
11868
11869
1/2
✓ Branch 0 taken 2083635 times.
✗ Branch 1 not taken.
2083635 DBUG_DUMP("table->read_set", (uchar *)table->read_set->bitmap,
11870 (table->s->fields + 7) / 8);
11871
1/2
✓ Branch 0 taken 2083635 times.
✗ Branch 1 not taken.
2083635 size_t const len = pack_row(table, table->read_set, row_data, record,
11872 enum_row_image_type::DELETE_BI);
11873
11874 Rows_log_event *const ev =
11875
1/2
✓ Branch 0 taken 2083635 times.
✗ Branch 1 not taken.
2083635 binlog_prepare_pending_rows_event<Delete_rows_log_event>(
11876 table, server_id, len, is_trans, extra_row_info);
11877
11878
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2083633 times.
2083635 if (unlikely(ev == nullptr)) return HA_ERR_OUT_OF_MEM;
11879
11880
1/2
✓ Branch 0 taken 2083633 times.
✗ Branch 1 not taken.
2083633 error = ev->add_row_data(row_data, len);
11881
11882 /* restore read/write set for the rest of execution */
11883 2083633 table->column_bitmaps_set_no_signal(old_read_set, old_write_set);
11884
11885 2083633 bitmap_clear_all(&table->tmp_set);
11886 2083633 return error;
11887 2083635 }
11888
11889 5899159 void binlog_prepare_row_images(const THD *thd, TABLE *table) {
11890
1/2
✓ Branch 0 taken 5899160 times.
✗ Branch 1 not taken.
5899159 DBUG_TRACE;
11891 /**
11892 Remove from read_set spurious columns. The write_set has been
11893 handled before in table->mark_columns_needed_for_update.
11894 */
11895
11896
9/12
✓ Branch 0 taken 22686936 times.
✓ Branch 1 taken 12866 times.
✓ Branch 2 taken 22699801 times.
✓ Branch 3 taken 5899158 times.
✓ Branch 4 taken 5899159 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5899160 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 5899151 times.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
28598961 DBUG_PRINT_BITSET("debug", "table->read_set (before preparing): %s",
11897 table->read_set);
11898
11899 /**
11900 if there is a primary key in the table (ie, user declared PK or a
11901 non-null unique index) and we dont want to ship the entire image,
11902 and the handler involved supports this.
11903 */
11904 16060331 if (table->s->primary_key < MAX_KEY &&
11905
6/6
✓ Branch 0 taken 4262013 times.
✓ Branch 1 taken 1637146 times.
✓ Branch 2 taken 8655 times.
✓ Branch 3 taken 4253358 times.
✓ Branch 4 taken 8655 times.
✓ Branch 5 taken 5890504 times.
5907814 (thd->variables.binlog_row_image < BINLOG_ROW_IMAGE_FULL) &&
11906
2/4
✓ Branch 0 taken 8655 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8655 times.
✗ Branch 3 not taken.
8655 !ha_check_storage_engine_flag(table->s->db_type(),
11907 HTON_NO_BINLOG_ROW_OPT)) {
11908 /**
11909 Just to be sure that tmp_set is currently not in use as
11910 the read_set already.
11911 */
11912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8655 times.
8655 assert(table->read_set != &table->tmp_set);
11913 // Verify it's not used
11914
2/4
✓ Branch 0 taken 8655 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8655 times.
8655 assert(bitmap_is_clear_all(&table->tmp_set));
11915
11916
2/3
✓ Branch 0 taken 5178 times.
✓ Branch 1 taken 3477 times.
✗ Branch 2 not taken.
8655 switch (thd->variables.binlog_row_image) {
11917 5178 case BINLOG_ROW_IMAGE_MINIMAL:
11918 /* MINIMAL: Mark only PK */
11919
1/2
✓ Branch 0 taken 5178 times.
✗ Branch 1 not taken.
5178 table->mark_columns_used_by_index_no_reset(table->s->primary_key,
11920 &table->tmp_set);
11921 5178 break;
11922 3477 case BINLOG_ROW_IMAGE_NOBLOB:
11923 /**
11924 NOBLOB: Remove unnecessary BLOB fields from read_set
11925 (the ones that are not part of PK).
11926 */
11927
1/2
✓ Branch 0 taken 3477 times.
✗ Branch 1 not taken.
3477 bitmap_union(&table->tmp_set, table->read_set);
11928
2/2
✓ Branch 0 taken 12966 times.
✓ Branch 1 taken 3477 times.
16443 for (Field **ptr = table->field; *ptr; ptr++) {
11929 12966 Field *field = (*ptr);
11930
5/6
✓ Branch 0 taken 12966 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1486 times.
✓ Branch 3 taken 11480 times.
✓ Branch 4 taken 1088 times.
✓ Branch 5 taken 11878 times.
14452 if ((field->type() == MYSQL_TYPE_BLOB) &&
11931
2/2
✓ Branch 0 taken 1088 times.
✓ Branch 1 taken 398 times.
1486 !field->is_flag_set(PRI_KEY_FLAG))
11932 1088 bitmap_clear_bit(&table->tmp_set, field->field_index());
11933 }
11934 3477 break;
11935 default:
11936 assert(0); // impossible.
11937 }
11938
11939 /* set the temporary read_set */
11940 8655 table->column_bitmaps_set_no_signal(&table->tmp_set, table->write_set);
11941 }
11942
11943
9/12
✓ Branch 0 taken 22683569 times.
✓ Branch 1 taken 16233 times.
✓ Branch 2 taken 22699802 times.
✓ Branch 3 taken 5899159 times.
✓ Branch 4 taken 5899160 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5899160 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 5899151 times.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
28598961 DBUG_PRINT_BITSET("debug", "table->read_set (after preparing): %s",
11944 table->read_set);
11945 5899160 }
11946
11947 71531837 int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) {
11948
1/2
✓ Branch 0 taken 71535080 times.
✗ Branch 1 not taken.
71531837 DBUG_TRACE;
11949 /*
11950 We shall flush the pending event even if we are not in row-based
11951 mode: it might be the case that we left row-based mode before
11952 flushing anything (e.g., if we have explicitly locked tables).
11953 */
11954 #ifdef WITH_WSREP
11955
12/12
✓ Branch 0 taken 28924496 times.
✓ Branch 1 taken 42610584 times.
✓ Branch 2 taken 2561906 times.
✓ Branch 3 taken 26362590 times.
✓ Branch 4 taken 1674184 times.
✓ Branch 5 taken 887722 times.
✓ Branch 6 taken 1661530 times.
✓ Branch 7 taken 12654 times.
✓ Branch 8 taken 30979604 times.
✓ Branch 9 taken 40541797 times.
✓ Branch 10 taken 30979604 times.
✓ Branch 11 taken 40554451 times.
71535080 if (!(WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open())) return 0;
11956 #else
11957 if (!mysql_bin_log.is_open()) return 0;
11958 #endif /* WITH_WSREP */
11959
11960 /*
11961 Mark the event as the last event of a statement if the stmt_end
11962 flag is set.
11963 */
11964 40554451 int error = 0;
11965 40555154 if (Rows_log_event *pending =
11966
3/4
✓ Branch 0 taken 40555154 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4214335 times.
✓ Branch 3 taken 36340819 times.
40554451 binlog_get_pending_rows_event(is_transactional)) {
11967
1/2
✓ Branch 0 taken 4214340 times.
✗ Branch 1 not taken.
4214335 if (stmt_end) {
11968 4214340 pending->set_flags(Rows_log_event::STMT_END_F);
11969 4214282 binlog_table_maps = 0;
11970 }
11971
11972
1/2
✓ Branch 0 taken 4214358 times.
✗ Branch 1 not taken.
4214277 error = mysql_bin_log.flush_and_set_pending_rows_event(this, nullptr,
11973 is_transactional);
11974 }
11975
11976 40555177 return error;
11977 71534781 }
11978
11979 #if !defined(NDEBUG)
11980 117 static const char *show_query_type(THD::enum_binlog_query_type qtype) {
11981
2/3
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
117 switch (qtype) {
11982 27 case THD::ROW_QUERY_TYPE:
11983 27 return "ROW";
11984 90 case THD::STMT_QUERY_TYPE:
11985 90 return "STMT";
11986 case THD::QUERY_TYPE_COUNT:
11987 default:
11988 assert(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
11989 }
11990 static char buf[64];
11991 sprintf(buf, "UNKNOWN#%d", qtype);
11992 return buf;
11993 }
11994 #endif
11995
11996 /**
11997 Auxiliary function to reset the limit unsafety warning suppression.
11998 */
11999 static void reset_binlog_unsafe_suppression() {
12000 DBUG_TRACE;
12001 unsafe_warning_suppression_is_activated = false;
12002 limit_unsafe_warning_count = 0;
12003 limit_unsafe_suppression_start_time = my_getsystime() / 10000000;
12004 }
12005
12006 /**
12007 Auxiliary function to print warning in the error log.
12008 */
12009 2533 static void print_unsafe_warning_to_log(int unsafe_type, char *buf,
12010 const char *query) {
12011
1/2
✓ Branch 0 taken 2533 times.
✗ Branch 1 not taken.
2533 DBUG_TRACE;
12012
1/2
✓ Branch 0 taken 2533 times.
✗ Branch 1 not taken.
2533 sprintf(buf, ER_DEFAULT(ER_BINLOG_UNSAFE_STATEMENT),
12013
1/2
✓ Branch 0 taken 2533 times.
✗ Branch 1 not taken.
2533 ER_DEFAULT_NONCONST(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
12014
8/16
✓ Branch 0 taken 2533 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2533 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2533 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2533 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2533 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2533 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2533 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2533 times.
✗ Branch 15 not taken.
2533 LogErr(WARNING_LEVEL, ER_BINLOG_UNSAFE_MESSAGE_AND_STATEMENT, buf, query);
12015 2533 }
12016
12017 /**
12018 Auxiliary function to check if the warning for limit unsafety should be
12019 thrown or suppressed. Details of the implementation can be found in the
12020 comments inline.
12021
12022 @param buf Buffer to hold the warning message text
12023 @param unsafe_type The type of unsafety.
12024 @param query The actual query statement.
12025
12026 TODO: Remove this function and implement a general service for all warnings
12027 that would prevent flooding the error log. => switch to log_throttle class?
12028 */
12029 282 static void do_unsafe_limit_checkout(char *buf, int unsafe_type,
12030 const char *query) {
12031 ulonglong now;
12032
1/2
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
282 DBUG_TRACE;
12033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 282 times.
282 assert(unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT);
12034 282 limit_unsafe_warning_count++;
12035 /*
12036 INITIALIZING:
12037 If this is the first time this function is called with log warning
12038 enabled, the monitoring the unsafe warnings should start.
12039 */
12040
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 273 times.
282 if (limit_unsafe_suppression_start_time == 0) {
12041 9 limit_unsafe_suppression_start_time = my_getsystime() / 10000000;
12042
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 print_unsafe_warning_to_log(unsafe_type, buf, query);
12043 } else {
12044
1/2
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
273 if (!unsafe_warning_suppression_is_activated)
12045
1/2
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
273 print_unsafe_warning_to_log(unsafe_type, buf, query);
12046
12047
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 269 times.
273 if (limit_unsafe_warning_count >=
12048 LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT) {
12049 4 now = my_getsystime() / 10000000;
12050
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!unsafe_warning_suppression_is_activated) {
12051 /*
12052 ACTIVATION:
12053 We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT warnings in
12054 less than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT we activate the
12055 suppression.
12056 */
12057
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if ((now - limit_unsafe_suppression_start_time) <=
12058 LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) {
12059 unsafe_warning_suppression_is_activated = true;
12060 DBUG_PRINT("info", ("A warning flood has been detected and the "
12061 "limit unsafety warning suppression has been "
12062 "activated."));
12063 } else {
12064 /*
12065 there is no flooding till now, therefore we restart the monitoring
12066 */
12067 4 limit_unsafe_suppression_start_time = my_getsystime() / 10000000;
12068 4 limit_unsafe_warning_count = 0;
12069 }
12070 } else {
12071 /*
12072 Print the suppression note and the unsafe warning.
12073 */
12074 LogErr(INFORMATION_LEVEL, ER_BINLOG_WARNING_SUPPRESSED,
12075 limit_unsafe_warning_count,
12076 (int)(now - limit_unsafe_suppression_start_time));
12077 print_unsafe_warning_to_log(unsafe_type, buf, query);
12078 /*
12079 DEACTIVATION: We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT
12080 warnings in more than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT, the
12081 suppression should be deactivated.
12082 */
12083 if ((now - limit_unsafe_suppression_start_time) >
12084 LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) {
12085 reset_binlog_unsafe_suppression();
12086 DBUG_PRINT("info", ("The limit unsafety warning supression has "
12087 "been deactivated"));
12088 }
12089 }
12090 4 limit_unsafe_warning_count = 0;
12091 }
12092 }
12093 282 }
12094
12095 /**
12096 Auxiliary method used by @c binlog_query() to raise warnings.
12097
12098 The type of warning and the type of unsafeness is stored in
12099 THD::binlog_unsafe_warning_flags.
12100 */
12101 1533861 void THD::issue_unsafe_warnings() {
12102 char buf[MYSQL_ERRMSG_SIZE * 2];
12103
1/2
✓ Branch 0 taken 1534070 times.
✗ Branch 1 not taken.
1533861 DBUG_TRACE;
12104 /*
12105 Ensure that binlog_unsafe_warning_flags is big enough to hold all
12106 bits. This is actually a constant expression.
12107 */
12108 assert(LEX::BINLOG_STMT_UNSAFE_COUNT <=
12109 sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
12110
12111 1534070 uint32 unsafe_type_flags = binlog_unsafe_warning_flags;
12112
12113
2/2
✓ Branch 0 taken 577 times.
✓ Branch 1 taken 1533493 times.
1534070 if ((unsafe_type_flags & (1U << LEX::BINLOG_STMT_UNSAFE_LIMIT)) != 0) {
12114
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 75 times.
577 if ((lex->sql_command == SQLCOM_DELETE ||
12115
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 439 times.
502 lex->sql_command == SQLCOM_UPDATE) &&
12116
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 lex->query_block->select_limit) {
12117 276 ORDER *order = (ORDER *)((lex->query_block->order_list.elements)
12118
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 35 times.
138 ? lex->query_block->order_list.first
12119 : nullptr);
12120 414 if ((lex->query_block->select_limit &&
12121
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 lex->query_block->select_limit->fixed &&
12122
5/8
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 83 times.
✓ Branch 7 taken 55 times.
414 lex->query_block->select_limit->val_int() == 0) ||
12123
3/4
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 55 times.
138 is_order_deterministic(lex->query_tables,
12124 138 lex->query_block->where_cond(), order)) {
12125 83 unsafe_type_flags &= ~(1U << LEX::BINLOG_STMT_UNSAFE_LIMIT);
12126 }
12127 }
12128
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 347 times.
577 if ((lex->sql_command == SQLCOM_INSERT_SELECT ||
12129
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 169 times.
230 lex->sql_command == SQLCOM_REPLACE_SELECT) &&
12130
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 197 times.
408 order_deterministic) {
12131 211 unsafe_type_flags &= ~(1U << LEX::BINLOG_STMT_UNSAFE_LIMIT);
12132 }
12133 }
12134
12135 /*
12136 For each unsafe_type, check if the statement is unsafe in this way
12137 and issue a warning.
12138 */
12139
2/2
✓ Branch 0 taken 39878379 times.
✓ Branch 1 taken 1538066 times.
41416445 for (int unsafe_type = 0; unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
12140 unsafe_type++) {
12141
2/2
✓ Branch 0 taken 13133 times.
✓ Branch 1 taken 39865246 times.
39878379 if ((unsafe_type_flags & (1 << unsafe_type)) != 0) {
12142
2/4
✓ Branch 0 taken 13133 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13133 times.
✗ Branch 3 not taken.
13133 push_warning_printf(
12143 this, Sql_condition::SL_NOTE, ER_BINLOG_UNSAFE_STATEMENT,
12144 ER_THD(this, ER_BINLOG_UNSAFE_STATEMENT),
12145
1/2
✓ Branch 0 taken 13133 times.
✗ Branch 1 not taken.
13133 ER_THD_NONCONST(this, LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
12146
4/4
✓ Branch 0 taken 2534 times.
✓ Branch 1 taken 10599 times.
✓ Branch 2 taken 2533 times.
✓ Branch 3 taken 1 times.
13133 if (log_error_verbosity > 1 && opt_log_unsafe_statements) {
12147
2/2
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 2251 times.
2533 if (unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT)
12148
2/4
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 282 times.
✗ Branch 3 not taken.
282 do_unsafe_limit_checkout(buf, unsafe_type, query().str);
12149 else // cases other than LIMIT unsafety
12150
2/4
✓ Branch 0 taken 2251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6247 times.
✗ Branch 3 not taken.
2251 print_unsafe_warning_to_log(unsafe_type, buf, query().str);
12151 }
12152 }
12153 }
12154 1538066 }
12155
12156 /**
12157 Log the current query.
12158
12159 The query will be logged in either row format or statement format
12160 depending on the value of @c current_stmt_binlog_format_row field and
12161 the value of the @c qtype parameter.
12162
12163 This function must be called:
12164
12165 - After the all calls to ha_*_row() functions have been issued.
12166
12167 - After any writes to system tables. Rationale: if system tables
12168 were written after a call to this function, and the master crashes
12169 after the call to this function and before writing the system
12170 tables, then the master and slave get out of sync.
12171
12172 - Before tables are unlocked and closed.
12173
12174 @see decide_logging_format
12175
12176 @retval 0 Success
12177
12178 @retval nonzero If there is a failure when writing the query (e.g.,
12179 write failure), then the error code is returned.
12180 */
12181 5020840 int THD::binlog_query(THD::enum_binlog_query_type qtype, const char *query_arg,
12182 size_t query_len, bool is_trans, bool direct,
12183 bool suppress_use, int errcode) {
12184
1/2
✓ Branch 0 taken 5021262 times.
✗ Branch 1 not taken.
5020840 DBUG_TRACE;
12185
4/8
✓ Branch 0 taken 5021211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5021217 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 117 times.
✓ Branch 5 taken 5021100 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5021262 DBUG_PRINT("enter",
12186 ("qtype: %s query: '%s'", show_query_type(qtype), query_arg));
12187 #ifdef WITH_WSREP
12188
10/12
✓ Branch 0 taken 5021017 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52433 times.
✓ Branch 3 taken 4968584 times.
✓ Branch 4 taken 52418 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 42507 times.
✓ Branch 7 taken 9911 times.
✓ Branch 8 taken 42387 times.
✓ Branch 9 taken 120 times.
✓ Branch 10 taken 5020979 times.
✗ Branch 11 not taken.
5021017 assert(query_arg &&
12189 (WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open()));
12190 #else
12191 assert(query_arg && mysql_bin_log.is_open());
12192 #endif /* WITH_WSREP */
12193
12194
2/2
✓ Branch 0 taken 7744 times.
✓ Branch 1 taken 5013371 times.
5021099 if (get_binlog_local_stmt_filter() == BINLOG_FILTER_SET) {
12195 /*
12196 The current statement is to be ignored, and not written to
12197 the binlog. Do not call issue_unsafe_warnings().
12198 */
12199 7744 return 0;
12200 }
12201
12202 /*
12203 If we are not in prelocked mode, mysql_unlock_tables() will be
12204 called after this binlog_query(), so we have to flush the pending
12205 rows event with the STMT_END_F set to unlock all tables at the
12206 slave side as well.
12207
12208 If we are in prelocked mode, the flushing will be done inside the
12209 top-most close_thread_tables().
12210 */
12211
2/2
✓ Branch 0 taken 4914890 times.
✓ Branch 1 taken 98481 times.
5013371 if (this->locked_tables_mode <= LTM_LOCK_TABLES)
12212
3/4
✓ Branch 0 taken 4914978 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 4914955 times.
4914890 if (int error = binlog_flush_pending_rows_event(true, is_trans))
12213 23 return error;
12214
12215 /*
12216 Warnings for unsafe statements logged in statement format are
12217 printed in three places instead of in decide_logging_format().
12218 This is because the warnings should be printed only if the statement
12219 is actually logged. When executing decide_logging_format(), we cannot
12220 know for sure if the statement will be logged:
12221
12222 1 - sp_head::execute_procedure which prints out warnings for calls to
12223 stored procedures.
12224
12225 2 - sp_head::execute_function which prints out warnings for calls
12226 involving functions.
12227
12228 3 - THD::binlog_query (here) which prints warning for top level
12229 statements not covered by the two cases above: i.e., if not inside a
12230 procedure and a function.
12231
12232 Besides, we should not try to print these warnings if it is not
12233 possible to write statements to the binary log as it happens when
12234 the execution is inside a function, or generally speaking, when
12235 the variables.option_bits & OPTION_BIN_LOG is false.
12236 */
12237
4/4
✓ Branch 0 taken 4768100 times.
✓ Branch 1 taken 245336 times.
✓ Branch 2 taken 1524608 times.
✓ Branch 3 taken 3243492 times.
5013436 if ((variables.option_bits & OPTION_BIN_LOG) && sp_runtime_ctx == nullptr &&
12238
1/2
✓ Branch 0 taken 1524844 times.
✗ Branch 1 not taken.
1524608 !binlog_evt_union.do_union) {
12239
1/2
✓ Branch 0 taken 1524868 times.
✗ Branch 1 not taken.
1524844 issue_unsafe_warnings();
12240 1524868 order_deterministic = true;
12241 }
12242
12243
2/3
✓ Branch 0 taken 4546166 times.
✓ Branch 1 taken 467294 times.
✗ Branch 2 not taken.
5013460 switch (qtype) {
12244 /*
12245 ROW_QUERY_TYPE means that the statement may be logged either in
12246 row format or in statement format. If
12247 current_stmt_binlog_format is row, it means that the
12248 statement has already been logged in row format and hence shall
12249 not be logged again.
12250 */
12251 4546166 case THD::ROW_QUERY_TYPE:
12252
5/8
✓ Branch 0 taken 4546157 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4546171 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 4546144 times.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
4546166 DBUG_PRINT("debug", ("is_current_stmt_binlog_format_row: %d",
12253 is_current_stmt_binlog_format_row()));
12254
2/2
✓ Branch 0 taken 4168819 times.
✓ Branch 1 taken 377330 times.
4546171 if (is_current_stmt_binlog_format_row()) return 0;
12255 [[fallthrough]];
12256
12257 /*
12258 STMT_QUERY_TYPE means that the query must be logged in statement
12259 format; it cannot be logged in row format. This is typically
12260 used by DDL statements. It is an error to use this query type
12261 if current_stmt_binlog_format_row is row.
12262
12263 @todo Currently there are places that call this method with
12264 STMT_QUERY_TYPE and current_stmt_binlog_format is row. Fix those
12265 places and add assert to ensure correct behavior. /Sven
12266 */
12267 case THD::STMT_QUERY_TYPE:
12268 /*
12269 The MYSQL_BIN_LOG::write() function will set the STMT_END_F flag and
12270 flush the pending rows event if necessary.
12271 */
12272 {
12273 Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
12274
1/2
✓ Branch 0 taken 844439 times.
✗ Branch 1 not taken.
844624 suppress_use, errcode);
12275 /*
12276 Binlog table maps will be irrelevant after a Query_log_event
12277 (they are just removed on the slave side) so after the query
12278 log event is written to the binary log, we pretend that no
12279 table maps were written.
12280 */
12281
1/2
✓ Branch 0 taken 844553 times.
✗ Branch 1 not taken.
844439 int error = mysql_bin_log.write_event(&qinfo);
12282 844553 binlog_table_maps = 0;
12283 844553 return error;
12284 844553 }
12285 break;
12286
12287 case THD::QUERY_TYPE_COUNT:
12288 default:
12289 assert(0 <= qtype && qtype < QUERY_TYPE_COUNT);
12290 }
12291 return 0;
12292 5021247 }
12293
12294 #ifdef WITH_WSREP
12295 52212 int prepend_binlog_control_event(THD *const thd) {
12296 52212 unsigned char *read_pos = nullptr;
12297 52212 my_off_t read_len = 0;
12298
12299
2/2
✓ Branch 0 taken 52196 times.
✓ Branch 1 taken 16 times.
52212 if ((thd->variables.option_bits & OPTION_BIN_LOG) != 0) return 0;
12300
12301
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 IO_CACHE_binlog_cache_storage tmp_io_cache;
12302
3/6
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
16 if (tmp_io_cache.open(mysql_tmpdir, TEMP_PREFIX, 128, 128))
12303 return ER_ERROR_ON_WRITE;
12304
12305 16 int ret = 0;
12306
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 Intvar_log_event ev((uchar)binary_log::Intvar_event::BINLOG_CONTROL_EVENT, 0);
12307
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
16 if (ev.write(&tmp_io_cache)) {
12308 ret = ER_ERROR_ON_WRITE;
12309 goto cleanup;
12310 }
12311
12312
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
16 if (tmp_io_cache.begin(&read_pos, &read_len)) {
12313 WSREP_ERROR("Failed to initialize io-cache");
12314 ret = ER_ERROR_ON_WRITE;
12315 goto cleanup;
12316 }
12317
12318
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 16 times.
16 if (read_len == 0 && tmp_io_cache.next(&read_pos, &read_len)) {
12319 WSREP_ERROR("Failed to read from io-cache");
12320 ret = ER_ERROR_ON_WRITE;
12321 goto cleanup;
12322 }
12323
12324
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 if (thd->wsrep_cs().append_data(wsrep::const_buffer(read_pos, read_len))) {
12325 WSREP_ERROR("Failed to append writeset data");
12326 ret = ER_ERROR_ON_WRITE;
12327 }
12328
12329 16 cleanup:
12330
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 tmp_io_cache.close();
12331 16 return ret;
12332 16 }
12333
12334 965608 IO_CACHE_binlog_cache_storage *wsrep_get_trans_cache(THD *thd,
12335 bool transaction) {
12336 965608 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
12337
1/2
✓ Branch 0 taken 965609 times.
✗ Branch 1 not taken.
965609 if (cache_mngr) {
12338
1/2
✓ Branch 0 taken 965609 times.
✗ Branch 1 not taken.
965609 if (transaction)
12339 965609 return cache_mngr->get_trx_cache()->io_cache();
12340 else
12341 return cache_mngr->get_stmt_cache()->io_cache();
12342 } else {
12343 WSREP_DEBUG("binlog cache not initialized, conn :%u", thd->thread_id());
12344 return NULL;
12345 }
12346 }
12347
12348 bool wsrep_trans_cache_is_empty(THD *thd) {
12349 binlog_cache_mngr *const cache_mngr =
12350 (binlog_cache_mngr *)thd_get_ha_data(thd, binlog_hton);
12351 return (!cache_mngr || cache_mngr->trx_cache.is_binlog_empty());
12352 }
12353
12354 void wsrep_thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end) {
12355 thd->binlog_flush_pending_rows_event(stmt_end);
12356 }
12357
12358 3979 void wsrep_thd_binlog_trx_reset(THD *thd) {
12359 /*
12360 TODO: fix autocommit select to not call the caller
12361 */
12362
2/2
✓ Branch 0 taken 293 times.
✓ Branch 1 taken 3686 times.
3979 if (thd_get_ha_data(thd, binlog_hton) != NULL) {
12363 293 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
12364
1/2
✓ Branch 0 taken 293 times.
✗ Branch 1 not taken.
293 if (cache_mngr) {
12365 293 cache_mngr->trx_cache.reset();
12366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 293 times.
293 if (!cache_mngr->stmt_cache.is_binlog_empty()) {
12367 WSREP_DEBUG("pending events in stmt cache, sql: %s", WSREP_QUERY(thd));
12368 cache_mngr->stmt_cache.reset();
12369 }
12370 }
12371 }
12372 3979 thd->clear_binlog_table_maps();
12373 3979 }
12374
12375 7933491 TC_LOG::enum_result wsrep_thd_binlog_commit(THD *thd, bool all) {
12376 /* binlog commit is called for wsrep replication to happen
12377 - applier and replayer can skip binlog commit
12378 - also if node is not joined, replication must be skipped
12379 */
12380
13/14
✓ Branch 0 taken 7933494 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5326401 times.
✓ Branch 3 taken 2607093 times.
✓ Branch 4 taken 127629 times.
✓ Branch 5 taken 5198772 times.
✓ Branch 6 taken 17952 times.
✓ Branch 7 taken 109677 times.
✓ Branch 8 taken 4728 times.
✓ Branch 9 taken 13224 times.
✓ Branch 10 taken 4480 times.
✓ Branch 11 taken 248 times.
✓ Branch 12 taken 3147 times.
✓ Branch 13 taken 7930347 times.
7937974 if (WSREP_EMULATE_BINLOG(thd) && !wsrep_thd_is_applying(thd) &&
12381
2/2
✓ Branch 0 taken 3147 times.
✓ Branch 1 taken 1336 times.
4480 wsrep_ready_get())
12382 3147 return mysql_bin_log.commit(thd, all);
12383 else {
12384
2/2
✓ Branch 0 taken 2304853 times.
✓ Branch 1 taken 5625494 times.
7930347 if (all) {
12385
2/4
✓ Branch 0 taken 2304867 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2304888 times.
✗ Branch 3 not taken.
2304853 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_commit_in_tc");
12386 }
12387
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 7930310 times.
7930386 return trx_coordinator::commit_in_engines(thd, all) ? TC_LOG::RESULT_ABORTED
12388 7930367 : TC_LOG::RESULT_SUCCESS;
12389 }
12390 }
12391
12392 267761 int wsrep_thd_binlog_rollback(THD *thd, bool all) {
12393 /* binlog rollback is called for wsrep replication to happen
12394 - applier and replayer can skip binlog commit
12395 - also if node is not joined, replication must be skipped
12396 */
12397
13/14
✓ Branch 0 taken 267762 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 237164 times.
✓ Branch 3 taken 30598 times.
✓ Branch 4 taken 10369 times.
✓ Branch 5 taken 226795 times.
✓ Branch 6 taken 8500 times.
✓ Branch 7 taken 1869 times.
✓ Branch 8 taken 1581 times.
✓ Branch 9 taken 6919 times.
✓ Branch 10 taken 1576 times.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 705 times.
✓ Branch 13 taken 267060 times.
269342 if (WSREP_EMULATE_BINLOG(thd) && !wsrep_thd_is_applying(thd) &&
12398
2/2
✓ Branch 0 taken 705 times.
✓ Branch 1 taken 876 times.
1576 wsrep_ready_get())
12399 705 return mysql_bin_log.rollback(thd, all);
12400 else {
12401
2/2
✓ Branch 0 taken 230505 times.
✓ Branch 1 taken 36555 times.
267060 if (all) {
12402
2/4
✓ Branch 0 taken 230521 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 230505 times.
✗ Branch 3 not taken.
230505 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_rollback_in_tc");
12403 }
12404 267069 return trx_coordinator::rollback_in_engines(thd, all);
12405 }
12406 }
12407
12408 6 bool wsrep_stmt_rollback_is_safe(THD *thd) {
12409 6 bool ret(true);
12410
12411
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_TRACE;
12412
12413 binlog_cache_mngr *cache_mngr =
12414
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 (binlog_cache_mngr *)thd_get_ha_data(thd, binlog_hton);
12415
12416
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (binlog_hton && cache_mngr) {
12417
4/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
14 if (thd->wsrep_sr().fragments_certified() > 0 &&
12418
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
8 (cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF ||
12419 2 cache_mngr->trx_cache.get_prev_position() <
12420 2 thd->wsrep_sr().log_position())) {
12421
1/26
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
6 WSREP_DEBUG(
12422 "statement rollback is not safe for streaming replication"
12423 " pre-stmt_pos: %llu, frag repl pos: %zu\n"
12424 "Thread: %u, SQL: %s",
12425 cache_mngr->trx_cache.get_prev_position(),
12426 thd->wsrep_sr().log_position(), thd->thread_id(), thd->query().str);
12427 6 ret = false;
12428 }
12429 }
12430 6 return ret;
12431 6 }
12432
12433 void wsrep_register_binlog_handler(THD *thd, bool trx) {
12434 DBUG_TRACE;
12435 /*
12436 If this is the first call to this function while processing a statement,
12437 the transactional cache does not have a savepoint defined. So, in what
12438 follows:
12439 . an implicit savepoint is defined;
12440 . callbacks are registered;
12441 . binary log is set as read/write.
12442
12443 The savepoint allows for truncating the trx-cache transactional changes
12444 fail. Callbacks are necessary to flush caches upon committing or rolling
12445 back a statement or a transaction. However, notifications do not happen
12446 if the binary log is set as read/write.
12447 */
12448 // binlog_cache_mngr *cache_mngr= thd_get_cache_mngr(thd);
12449 binlog_cache_mngr *cache_mngr =
12450 (binlog_cache_mngr *)thd_get_ha_data(thd, binlog_hton);
12451 /* cache_mngr may be missing e.g. in mtr test ev51914.test */
12452 if (cache_mngr &&
12453 cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF) {
12454 /*
12455 Set an implicit savepoint in order to be able to truncate a trx-cache.
12456 */
12457 my_off_t pos = 0;
12458 binlog_trans_log_savepos(thd, &pos);
12459 cache_mngr->trx_cache.set_prev_position(pos);
12460
12461 /*
12462 Set callbacks in order to be able to call commmit or rollback.
12463 */
12464 if (trx) trans_register_ha(thd, true, binlog_hton, NULL);
12465 trans_register_ha(thd, false, binlog_hton, NULL);
12466
12467 /*
12468 Set the binary log as read/write otherwise callbacks are not called.
12469 */
12470 thd->get_ha_data(binlog_hton->slot)->ha_info[0].set_trx_read_write();
12471 }
12472 return;
12473 }
12474
12475 #endif /* WITH_WSREP */
12476
12477 284402 static const binlog_cache_mngr *get_cache_mngr(THD *thd) {
12478 const binlog_cache_mngr *cache_mngr =
12479
2/2
✓ Branch 0 taken 280510 times.
✓ Branch 1 taken 3892 times.
284402 (thd && opt_bin_log)
12480
1/2
✓ Branch 0 taken 284402 times.
✗ Branch 1 not taken.
568804 ? static_cast<binlog_cache_mngr *>(thd_get_ha_data(thd, binlog_hton))
12481 284402 : nullptr;
12482
12483 284402 return cache_mngr;
12484 }
12485
12486 142201 static int show_binlog_vars(THD *thd, SHOW_VAR *var,
12487 char *buff [[maybe_unused]]) {
12488 mysql_mutex_assert_owner(&LOCK_status);
12489
12490 142201 const binlog_cache_mngr *cache_mngr = get_cache_mngr(thd);
12491
12492
6/6
✓ Branch 0 taken 19529 times.
✓ Branch 1 taken 122672 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 19481 times.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 142153 times.
142201 if (cache_mngr && cache_mngr->has_consistent_snapshot()) {
12493 48 set_binlog_snapshot_file(cache_mngr->binlog_info.log_file_name);
12494 48 binlog_snapshot_position = cache_mngr->binlog_info.pos;
12495
2/2
✓ Branch 0 taken 140207 times.
✓ Branch 1 taken 1946 times.
142153 } else if (mysql_bin_log.is_open()) {
12496 140207 set_binlog_snapshot_file(binlog_global_snapshot_file);
12497 140207 binlog_snapshot_position = binlog_global_snapshot_position;
12498 } else {
12499 1946 binlog_snapshot_file[0] = '\0';
12500 1946 binlog_snapshot_position = 0;
12501 }
12502 142201 var->type = SHOW_ARRAY;
12503 142201 var->value = reinterpret_cast<char *>(&binlog_status_vars_detail);
12504 142201 return 0;
12505 }
12506
12507 142201 static int show_binlog_snapshot_gtid_executed(
12508 THD *thd, SHOW_VAR *var, char *buff [[maybe_unused]]) {
12509 mysql_mutex_assert_owner(&LOCK_status);
12510
12511 142201 const binlog_cache_mngr *cache_mngr = get_cache_mngr(thd);
12512
12513
6/6
✓ Branch 0 taken 19529 times.
✓ Branch 1 taken 122672 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 19481 times.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 142153 times.
142201 if (cache_mngr && cache_mngr->has_consistent_snapshot()) {
12514 48 binlog_snapshot_gtid_executed = cache_mngr->snapshot_gtid_executed;
12515
2/2
✓ Branch 0 taken 140207 times.
✓ Branch 1 taken 1946 times.
142153 } else if (mysql_bin_log.is_open()) {
12516 140207 binlog_snapshot_gtid_executed = "not-in-consistent-snapshot";
12517 } else {
12518 1946 binlog_snapshot_gtid_executed.clear();
12519 }
12520
12521 142201 var->type = SHOW_CHAR;
12522 142201 var->value = const_cast<char *>(binlog_snapshot_gtid_executed.c_str());
12523 142201 return 0;
12524 }
12525
12526 static SHOW_VAR binlog_status_vars_top[] = {
12527 {"Binlog", (char *)&show_binlog_vars, SHOW_FUNC, SHOW_SCOPE_GLOBAL},
12528 {"Binlog_snapshot_gtid_executed",
12529 (char *)&show_binlog_snapshot_gtid_executed, SHOW_FUNC, SHOW_SCOPE_GLOBAL},
12530 {NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL}};
12531
12532 namespace {
12533 5168894 void finish_transaction_in_engines(THD *thd, bool all, bool run_after_commit) {
12534
2/2
✓ Branch 0 taken 2583784 times.
✓ Branch 1 taken 2585030 times.
5168894 if (thd->get_transaction()->m_flags.commit_low) {
12535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2583782 times.
2583784 if (trx_coordinator::commit_in_engines(thd, all, run_after_commit))
12536 thd->commit_error = THD::CE_COMMIT_ERROR;
12537
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 2585140 times.
2585030 } else if (is_xa_rollback(thd)) {
12538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 289 times.
289 if (trx_coordinator::rollback_in_engines(thd, all))
12539 thd->commit_error = THD::CE_COMMIT_ERROR;
12540 }
12541 5169211 }
12542 } // namespace
12543
12544 struct st_mysql_storage_engine binlog_storage_engine = {
12545 MYSQL_HANDLERTON_INTERFACE_VERSION};
12546
12547 /** @} */
12548
12549 mysql_declare_plugin(binlog){
12550 MYSQL_STORAGE_ENGINE_PLUGIN,
12551 &binlog_storage_engine,
12552 "binlog",
12553 PLUGIN_AUTHOR_ORACLE,
12554 "This is a pseudo storage engine to represent the binlog in a transaction",
12555 PLUGIN_LICENSE_GPL,
12556 binlog_init, /* Plugin Init */
12557 nullptr, /* Plugin Check uninstall */
12558 binlog_deinit, /* Plugin Deinit */
12559 0x0100 /* 1.0 */,
12560 binlog_status_vars_top, /* status variables */
12561 nullptr, /* system variables */
12562 nullptr, /* config options */
12563 0,
12564 } mysql_declare_plugin_end;
12565